Move account state related logic into Account.

The account state is now managed mostly by the Account itself
instead of through Application. The gui can still control whether
an account is signed out or not.
This commit is contained in:
Christian Kamm 2014-12-11 15:43:48 +01:00
parent cc3f7995fb
commit a006c6962c
11 changed files with 231 additions and 152 deletions

View file

@ -165,8 +165,7 @@ void Application::slotLogin()
Account *a = AccountManager::instance()->account();
if (a) {
FolderMan::instance()->setupFolders();
_userTriggeredConnect = true;
slotCheckConnection();
a->setSignedOut(false);
}
}
@ -180,7 +179,7 @@ void Application::slotLogout()
FolderMan *folderMan = FolderMan::instance();
folderMan->setSyncEnabled(false);
folderMan->terminateSyncProcess();
a->setState(Account::SignedOut);
a->setSignedOut(true);
// show result
_gui->slotComputeOverallSyncStatus();
}
@ -190,12 +189,12 @@ void Application::slotAccountChanged(Account *newAccount, Account *oldAccount)
{
if (oldAccount) {
disconnect(oldAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotAccountStateChanged()));
disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotToggleFolderman(int)));
disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
connect(oldAccount->quotaInfo(), SIGNAL(quotaUpdated(qint64,qint64)),
_gui, SLOT(slotRefreshQuotaDisplay(qint64,qint64)));
}
connect(newAccount, SIGNAL(stateChanged(int)), _gui, SLOT(slotAccountStateChanged()));
connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotToggleFolderman(int)));
connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
connect(newAccount->quotaInfo(), SIGNAL(quotaUpdated(qint64,qint64)),
_gui, SLOT(slotRefreshQuotaDisplay(qint64,qint64)));
}
@ -226,20 +225,7 @@ void Application::slotCheckConnection()
Account *account = AccountManager::instance()->account();
if( account ) {
if (account->state() == Account::InvalidCredential
|| account->state() == Account::SignedOut) {
//Do not try to connect if we are logged out
if (!_userTriggeredConnect) {
return;
}
}
if (_conValidator)
_conValidator->deleteLater();
_conValidator = new ConnectionValidator(account);
connect( _conValidator, SIGNAL(connectionResult(ConnectionValidator::Status, QStringList)),
this, SLOT(slotConnectionValidatorResult(ConnectionValidator::Status, QStringList)) );
_conValidator->checkConnection();
account->checkConnectivity();
} else {
// let gui open the setup wizard
@ -249,28 +235,7 @@ void Application::slotCheckConnection()
}
}
void Application::slotCredentialsFetched()
{
Account *account = AccountManager::instance()->account();
Q_ASSERT(account);
if (!account) {
qDebug() << Q_FUNC_INFO << "No account!";
return;
}
disconnect(account->credentials(), SIGNAL(fetched()), this, SLOT(slotCredentialsFetched()));
if (!account->credentials()->ready()) {
// User canceled the connection or did not give a password
account->setState(Account::SignedOut);
return;
}
if (account->state() == Account::InvalidCredential) {
// Then we ask again for the credentials if they are wrong again
account->setState(Account::Disconnected);
}
slotCheckConnection();
}
void Application::slotToggleFolderman(int state)
void Application::slotAccountStateChanged(int state)
{
FolderMan* folderMan = FolderMan::instance();
switch (state) {
@ -280,7 +245,8 @@ void Application::slotToggleFolderman(int state)
folderMan->slotScheduleAllFolders();
break;
case Account::SignedOut:
case Account::InvalidCredential:
case Account::ConfigurationError:
case Account::NetworkError:
case Account::Disconnected:
qDebug() << "Disabling sync scheduler, terminating sync";
folderMan->setSyncEnabled(false);
@ -289,13 +255,15 @@ void Application::slotToggleFolderman(int state)
}
// Stop checking the connection if we're manually signed out or
// when the credentials are wrong.
// when the error is permanent.
if (state == Account::SignedOut
|| state == Account::InvalidCredential) {
|| state == Account::ConfigurationError) {
_checkConnectionTimer.stop();
} else if (! _checkConnectionTimer.isActive()) {
_checkConnectionTimer.start();
}
slotUpdateConnectionErrors(state);
}
void Application::slotCrash()
@ -303,19 +271,17 @@ void Application::slotCrash()
Utility::crash();
}
void Application::slotConnectionValidatorResult(ConnectionValidator::Status status,
const QStringList& errors)
void Application::slotUpdateConnectionErrors(int accountState)
{
qDebug() << "Connection Validator Result: " << ConnectionValidator::statusString(status);
bool isConnected = status == ConnectionValidator::Connected;
bool isConnected = accountState == Account::Connected;
if( !isConnected ) {
_startupNetworkError = ConnectionValidator::isNetworkError(status);
if (_userTriggeredConnect) {
_userTriggeredConnect = false;
}
_startupNetworkError = accountState == Account::NetworkError;
}
Account *account = AccountManager::instance()->account();
if (account) {
_gui->setConnectionErrors( isConnected, account->connectionErrors() );
}
_gui->setConnectionErrors( isConnected, errors );
}
void Application::slotownCloudWizardDone( int res )

View file

@ -73,16 +73,14 @@ signals:
protected slots:
void slotParseOptions( const QString&, QObject* );
void slotCheckConnection();
void slotConnectionValidatorResult(ConnectionValidator::Status,
const QStringList& errors);
void slotUpdateConnectionErrors(int accountState);
void slotStartUpdateDetector();
void slotUseMonoIconsChanged( bool );
void slotLogin();
void slotLogout();
void slotCleanup();
void slotAccountChanged(Account *newAccount, Account *oldAccount = 0);
void slotCredentialsFetched();
void slotToggleFolderman(int state);
void slotAccountStateChanged(int state);
void slotCrash();
private:
@ -90,8 +88,6 @@ private:
QPointer<ownCloudGui> _gui;
QPointer<ConnectionValidator> _conValidator;
Theme *_theme;
bool _helpOnly;

View file

@ -305,7 +305,6 @@ void Folder::slotRunEtagJob()
_requestEtagJob = new RequestEtagJob(account, remotePath(), this);
// check if the etag is different
QObject::connect(_requestEtagJob, SIGNAL(etagRetreived(QString)), this, SLOT(etagRetreived(QString)));
QObject::connect(_requestEtagJob, SIGNAL(networkError(QNetworkReply*)), this, SLOT(slotNetworkUnavailable()));
FolderMan::instance()->slotScheduleETagJob(alias(), _requestEtagJob);
// The _requestEtagJob is auto deleting itself on finish. Our guard pointer _requestEtagJob will then be null.
}
@ -324,15 +323,6 @@ void Folder::etagRetreived(const QString& etag)
}
}
void Folder::slotNetworkUnavailable()
{
Account *account = AccountManager::instance()->account();
if (account && account->state() == Account::Connected) {
account->setState(Account::Disconnected);
}
emit syncStateChange();
}
void Folder::bubbleUpSyncResult()
{
// count new, removed and updated items

View file

@ -178,7 +178,6 @@ private slots:
void slotRunEtagJob();
void etagRetreived(const QString &);
void slotNetworkUnavailable();
void slotAboutToPropagate(const SyncFileItemVector& );
void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done

View file

@ -74,6 +74,8 @@ Account::Account(AbstractSslErrorHandler *sslErrorHandler, QObject *parent)
, _credentials(0)
, _treatSslErrorsAsFailure(false)
, _state(Account::Disconnected)
, _connectionStatus(ConnectionValidator::Undefined)
, _waitingForNewCredentials(false)
, _davPath("remote.php/webdav/")
, _wasMigrated(false)
{
@ -365,42 +367,166 @@ void Account::setCredentialSetting(const QString &key, const QVariant &value)
}
}
int Account::state() const
Account::ConnectionStatus Account::connectionStatus() const
{
return _connectionStatus;
}
QStringList Account::connectionErrors() const
{
return _connectionErrors;
}
QString Account::connectionStatusString(ConnectionStatus status)
{
return ConnectionValidator::statusString(status);
}
Account::State Account::state() const
{
return _state;
}
void Account::setState(int state)
void Account::setState(State state)
{
if (_state != state) {
qDebug() << "Account state change: "
<< stateString(_state) << "->" << stateString(state);
State oldState = _state;
_state = state;
emit stateChanged(state);
if (_state == SignedOut) {
_connectionStatus = ConnectionValidator::Undefined;
_connectionErrors.clear();
} else if (oldState == SignedOut && _state == Disconnected) {
checkConnectivity();
}
emit stateChanged(_state);
}
}
QString Account::stateString(int state)
QString Account::stateString(State state)
{
switch (state)
{
case Connected:
return QLatin1String("Connected");
case Disconnected:
return QLatin1String("Disconnected");
case SignedOut:
return QLatin1String("SignedOut");
case InvalidCredential:
return QLatin1String("InvalidCredential");
case Disconnected:
return QLatin1String("Disconnected");
case Connected:
return QLatin1String("Connected");
case NetworkError:
return QLatin1String("NetworkError");
case ConfigurationError:
return QLatin1String("ConfigurationError");
}
return QLatin1String("Unknown");
}
bool Account::isSignedOut() const
{
return _state == SignedOut;
}
void Account::setSignedOut(bool signedOut)
{
if (signedOut) {
setState(SignedOut);
} else {
setState(Disconnected);
}
}
QuotaInfo *Account::quotaInfo()
{
return _quotaInfo;
}
void Account::checkConnectivity()
{
if (isSignedOut() || _waitingForNewCredentials) {
return;
}
ConnectionValidator * conValidator = new ConnectionValidator(this);
connect(conValidator, SIGNAL(connectionResult(ConnectionValidator::Status,QStringList)),
SLOT(slotConnectionValidatorResult(ConnectionValidator::Status,QStringList)));
conValidator->checkConnection();
}
void Account::slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList& errors)
{
if (isSignedOut()) {
return;
}
switch (status)
{
case ConnectionValidator::Connected:
setState(Connected);
break;
case ConnectionValidator::Undefined:
case ConnectionValidator::NotConfigured:
setState(Disconnected);
break;
case ConnectionValidator::ServerVersionMismatch:
case ConnectionValidator::StatusNotFound:
setState(ConfigurationError);
break;
case ConnectionValidator::CredentialsWrong:
handleInvalidCredentials();
break;
case ConnectionValidator::Timeout:
setState(NetworkError);
break;
}
_connectionErrors = errors;
if (_connectionStatus != status) {
qDebug() << "Account connection status change: "
<< connectionStatusString(_connectionStatus) << "->"
<< connectionStatusString(status);
_connectionStatus = status;
}
}
void Account::handleInvalidCredentials()
{
if (isSignedOut()) {
return;
}
setState(ConfigurationError);
_waitingForNewCredentials = true;
// invalidate & forget token/password
// but try to re-sign in.
connect(_credentials, SIGNAL(fetched()),
SLOT(slotCredentialsFetched()), Qt::UniqueConnection);
if (_credentials->ready()) {
_credentials->invalidateAndFetch(this);
} else {
_credentials->fetch(this);
}
}
void Account::slotCredentialsFetched()
{
_waitingForNewCredentials = false;
disconnect(_credentials, SIGNAL(fetched()),
this, SLOT(slotCredentialsFetched()));
if (!_credentials->ready()) {
// User canceled the connection or did not give a password
setState(SignedOut);
return;
}
checkConnectivity();
}
void Account::slotHandleErrors(QNetworkReply *reply , QList<QSslError> errors)
{
NetworkJobTimeoutPauser pauser(reply);

View file

@ -23,6 +23,7 @@
#include <QSslConfiguration>
#include <QSslError>
#include "utility.h"
#include "connectionvalidator.h"
class QSettings;
class QNetworkReply;
@ -68,11 +69,28 @@ public:
class OWNCLOUDSYNC_EXPORT Account : public QObject {
Q_OBJECT
public:
enum State { Disconnected = 0, /// no network connection
Connected, /// account is online
SignedOut, /// Disconnected + credential token has been discarded
InvalidCredential /// The credentials are invalid and we are asking the user for them
};
enum State {
/// Not even attempting to connect, most likely because the
/// user explicitly signed out or cancelled a credential dialog.
SignedOut,
/// Account would like to be connected but hasn't heard back yet.
Disconnected,
/// The account is successfully talking to the server.
Connected,
/// Could not communicate with the server for some reason.
/// We assume this may resolve itself over time and will try
/// again automatically.
NetworkError,
/// An error like invalid credentials where retrying won't help.
ConfigurationError
};
/// The actual current connectivity status.
typedef ConnectionValidator::Status ConnectionStatus;
QString davPath() const { return _davPath; }
void setDavPath(const QString&s) { _davPath = s; }
@ -146,9 +164,15 @@ public:
QVariant credentialSetting(const QString& key) const;
void setCredentialSetting(const QString& key, const QVariant &value);
int state() const;
void setState(int state);
static QString stateString(int state);
ConnectionStatus connectionStatus() const;
QStringList connectionErrors() const;
static QString connectionStatusString(ConnectionStatus status);
State state() const;
static QString stateString(State status);
bool isSignedOut() const;
void setSignedOut(bool signedOut);
void clearCookieJar();
@ -156,12 +180,24 @@ public:
QuotaInfo *quotaInfo();
/// Triggers a ping to the server to update state and
/// connection status and errors.
void checkConnectivity();
/// Called when a request fails because of a credential error.
void handleInvalidCredentials();
private:
void setState(State state);
signals:
void stateChanged(int state);
void propagatorNetworkActivity();
protected Q_SLOTS:
void slotHandleErrors(QNetworkReply*,QList<QSslError>);
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList& errors);
void slotCredentialsFetched();
private:
QMap<QString, QVariant> _settingsMap;
@ -173,7 +209,10 @@ private:
QNetworkAccessManager *_am;
AbstractCredentials* _credentials;
bool _treatSslErrorsAsFailure;
int _state;
State _state;
ConnectionStatus _connectionStatus;
QStringList _connectionErrors;
bool _waitingForNewCredentials;
static QString _configFileName;
QString _davPath; // default "remote.php/webdav/";
bool _wasMigrated;

View file

@ -30,36 +30,28 @@ ConnectionValidator::ConnectionValidator(Account *account, QObject *parent)
QString ConnectionValidator::statusString( Status stat )
{
QString re;
switch( stat ) {
case Undefined:
re = QLatin1String("Undefined");
break;
return QLatin1String("Undefined");
case Connected:
re = QLatin1String("Connected");
break;
return QLatin1String("Connected");
case NotConfigured:
re = QLatin1String("NotConfigured");
break;
return QLatin1String("NotConfigured");
case ServerVersionMismatch:
re = QLatin1String("Server Version Mismatch");
break;
return QLatin1String("Server Version Mismatch");
case CredentialsWrong:
re = QLatin1String("Credentials Wrong");
break;
return QLatin1String("Credentials Wrong");
case StatusNotFound:
re = QLatin1String("Status not found");
break;
default:
re = QLatin1String("status undeclared.");
return QLatin1String("Status not found");
case Timeout:
return QLatin1String("Timeout");
}
return re;
return QLatin1String("status undeclared.");
}
bool ConnectionValidator::isNetworkError( Status status )
{
return status == StatusNotFound;
return status == Timeout;
}
void ConnectionValidator::checkConnection()
@ -70,7 +62,7 @@ void ConnectionValidator::checkConnection()
return;
}
if( _account->state() == Account::Connected ) {
if( _account->connectionStatus() == Connected ) {
// When we're already connected, just make sure a minimal request
// gets replied to.
slotCheckAuthentication();
@ -113,8 +105,6 @@ void ConnectionValidator::slotStatusFound(const QUrl&url, const QVariantMap &inf
// status.php could not be loaded.
void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
{
_account->setState(Account::Disconnected);
_errors.append(tr("Unable to connect to %1").arg(_account->url().toString()));
_errors.append( reply->errorString() );
reportResult( StatusNotFound );
@ -122,11 +112,9 @@ void ConnectionValidator::slotNoStatusFound(QNetworkReply *reply)
void ConnectionValidator::slotJobTimeout(const QUrl &url)
{
_account->setState(Account::Disconnected);
_errors.append(tr("Unable to connect to %1").arg(url.toString()));
_errors.append(tr("timeout"));
reportResult( StatusNotFound );
reportResult( Timeout );
}
@ -148,7 +136,7 @@ void ConnectionValidator::slotCheckAuthentication()
void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
{
Status stat = StatusNotFound;
Status stat = Timeout;
if( reply->error() == QNetworkReply::AuthenticationRequiredError ||
reply->error() == QNetworkReply::OperationCanceledError ) { // returned if the user/pwd is wrong.
@ -156,9 +144,6 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
qDebug() << "******** Password is wrong!";
_errors << tr("The provided credentials are not correct");
stat = CredentialsWrong;
if (_account->state() != Account::SignedOut) {
_account->setState(Account::Disconnected);
}
} else if( reply->error() != QNetworkReply::NoError ) {
_errors << reply->errorString();
@ -169,7 +154,6 @@ void ConnectionValidator::slotAuthFailed(QNetworkReply *reply)
void ConnectionValidator::slotAuthSuccess()
{
_account->setState(Account::Connected);
_errors.clear();
reportResult(Connected);
}

View file

@ -36,8 +36,9 @@ public:
NotConfigured,
ServerVersionMismatch,
CredentialsWrong,
// actually also used for timeouts or errors on the authed request
StatusNotFound
StatusNotFound,
// actually also used for other errors on the authed request
Timeout
};
void checkConnection();

View file

@ -166,7 +166,6 @@ void AbstractNetworkJob::slotFinished()
_responseTimestamp = QString::fromAscii(_reply->rawHeader("Date"));
_duration = _durationTimer.elapsed();
if (_followRedirects) {
// ### the qWarnings here should be exported via displayErrors() so they
// ### can be presented to the user if the job executor has a GUI
@ -188,22 +187,12 @@ void AbstractNetworkJob::slotFinished()
}
}
bool discard = finished();
AbstractCredentials *creds = _account->credentials();
if (!creds->stillValid(_reply) &&! _ignoreCredentialFailure
&& _account->state() != Account::InvalidCredential) {
_account->setState(Account::InvalidCredential);
// invalidate & forget token/password
// but try to re-sign in.
connect( creds, SIGNAL(fetched()),
qApp, SLOT(slotCredentialsFetched()), Qt::UniqueConnection);
if (creds->ready()) {
creds->invalidateAndFetch(_account);
} else {
creds->fetch(_account);
}
if (!creds->stillValid(_reply) && ! _ignoreCredentialFailure) {
_account->handleInvalidCredentials();
}
bool discard = finished();
if (discard) {
deleteLater();
}

View file

@ -34,29 +34,19 @@ QuotaInfo::QuotaInfo(Account *account)
, _lastQuotaUsedBytes(0)
, _jobRestartTimer(new QTimer(this))
{
connect(_account, SIGNAL(stateChanged(int)), SLOT(slotAccountStateChanged(int)));
connect(_account, SIGNAL(stateChanged(int)),
SLOT(slotAccountStateChanged(int)));
connect(_jobRestartTimer, SIGNAL(timeout()), SLOT(slotCheckQuota()));
_jobRestartTimer->setSingleShot(true);
_jobRestartTimer->start(initialTimeT);
}
void QuotaInfo::slotAccountChanged(Account *newAccount, Account *oldAccount)
{
_account = newAccount;
disconnect(oldAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
connect(newAccount, SIGNAL(stateChanged(int)), this, SLOT(slotAccountStateChanged(int)));
}
void QuotaInfo::slotAccountStateChanged(int state)
{
switch (state) {
case Account::SignedOut: // fall through
case Account::InvalidCredential:
case Account::Disconnected:
_jobRestartTimer->stop();
break;
case Account::Connected: // fall through
if (state == Account::Connected) {
slotCheckQuota();
} else {
_jobRestartTimer->stop();
}
}

View file

@ -36,7 +36,6 @@ public Q_SLOTS:
void slotCheckQuota();
private Q_SLOTS:
void slotAccountChanged(Account *newAccount, Account *oldAccount);
void slotAccountStateChanged(int state);
void slotRequestFailed();