Просмотр исходного кода

Merge remote-tracking branch 'knorr/xnat-session-timeout-signals' into xnat-session-timeout-handling

# Conflicts:
#	Applications/ctkXnatTreeBrowser/ctkXnatTreeBrowserMainWindow.cpp
#	Applications/ctkXnatTreeBrowser/ctkXnatTreeBrowserMainWindow.h
#	Libs/XNAT/Core/ctkXnatSession.cpp
#	Libs/XNAT/Core/ctkXnatSession.h
Andreas Fetzer лет назад: 9
Родитель
Сommit
27fe515e40

+ 39 - 0
Applications/ctkXnatTreeBrowser/ctkXnatTreeBrowserMainWindow.cpp

@@ -44,6 +44,10 @@
 #include <QFileDialog>
 #include <QFileInfo>
 
+#include <QMessageBox>
+#include <QDateTime>
+#include <QTimer>
+
 ctkXnatTreeBrowserMainWindow::ctkXnatTreeBrowserMainWindow(QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::ctkXnatTreeBrowserMainWindow),
@@ -54,6 +58,7 @@ ctkXnatTreeBrowserMainWindow::ctkXnatTreeBrowserMainWindow(QWidget *parent) :
 
   ui->treeView->setModel(m_TreeModel);
   ui->downloadLabel->hide();
+  ui->treeView->setHeaderHidden(true);
 
   this->connect(ui->loginButton, SIGNAL(clicked()), SLOT(loginButtonPushed()));
   this->connect(ui->treeView, SIGNAL(clicked(const QModelIndex&)), SLOT(itemSelected(const QModelIndex&)));
@@ -96,6 +101,8 @@ void ctkXnatTreeBrowserMainWindow::loginButtonPushed()
       {
         ui->loginButton->setText("Logout");
         ui->loginLabel->setText(QString("Connected: %1").arg(m_Session->url().toString()));
+        this->connect(m_Session, SIGNAL(sessionTimedOut()), this, SLOT(sessionTimedOutMsg()));
+        this->connect(m_Session, SIGNAL(sessionAboutToBeTimedOut()), this, SLOT(sessionTimesOutSoonMsg()));
 
         ctkXnatDataModel* dataModel = m_Session->dataModel();
         m_TreeModel->addDataModel(dataModel);
@@ -177,3 +184,35 @@ void ctkXnatTreeBrowserMainWindow::uploadFileClicked()
     m_TreeModel->addChildNode(index, file);
   }
 }
+
+void ctkXnatTreeBrowserMainWindow::sessionTimedOutMsg()
+{
+  ctkXnatDataModel* dataModel = m_Session->dataModel();
+  m_TreeModel->removeDataModel(dataModel);
+  ui->treeView->reset();
+  delete m_Session;
+  m_Session = 0;
+  ui->loginButton->setText("Login");
+  ui->loginLabel->setText("Disconnected");
+  ui->downloadLabel->hide();
+  QMessageBox::warning(this, "Session Timeout", "The session timed out.");
+}
+
+void ctkXnatTreeBrowserMainWindow::sessionTimesOutSoonMsg()
+{
+  QMessageBox msgBox;
+  msgBox.setIcon(QMessageBox::Warning);
+  msgBox.setWindowTitle("Session Timeout Soon");
+  msgBox.setText("The session will time out in 1 minute.\nDo you want to renew the session?");
+  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+  msgBox.setDefaultButton(QMessageBox::No);
+  msgBox.show();
+  QTimer* timer = new QTimer(this);
+  timer->start(60000);
+  this->connect(timer, SIGNAL(timeout()), &msgBox, SLOT(reject()));
+  if (msgBox.exec() == QMessageBox::Yes)
+  {
+    m_Session->renew();
+  }
+  timer->stop();
+}

+ 2 - 0
Applications/ctkXnatTreeBrowser/ctkXnatTreeBrowserMainWindow.h

@@ -48,6 +48,8 @@ private Q_SLOTS:
   void downloadButtonClicked();
   void addResourceClicked();
   void uploadFileClicked();
+  void sessionTimedOutMsg();
+  void sessionTimesOutSoonMsg();
 
 private:
   Ui::ctkXnatTreeBrowserMainWindow* ui;

+ 37 - 0
Libs/XNAT/Core/ctkXnatSession.cpp

@@ -37,6 +37,7 @@
 
 #include <QCryptographicHash>
 #include <QDateTime>
+#include <QTimer>
 #include <QDebug>
 #include <QDir>
 #include <QScopedPointer>
@@ -69,6 +70,14 @@ public:
 
   ctkXnatSession* q;
 
+  QTimer* timer;
+
+  // The time in milliseconds untill the signal sessionAboutToBeTimedOut gets emitted
+  int timeToSessionTimeOutWarning;
+
+  // The time in milliseconds untill the signal sessionTimedOut gets emitted
+  int timeToSessionTimedOut = 60000;
+
   ctkXnatSessionPrivate(const ctkXnatLoginProfile& loginProfile, ctkXnatSession* q);
   ~ctkXnatSessionPrivate();
 
@@ -92,6 +101,7 @@ ctkXnatSessionPrivate::ctkXnatSessionPrivate(const ctkXnatLoginProfile& loginPro
   , xnat(new ctkXnatAPI())
   , defaultDownloadDir(".")
   , q(q)
+  , timer(new QTimer(q))
 {
   // TODO This is a workaround for connecting to sites with self-signed
   // certificate. Should be replaced with something more clever.
@@ -212,8 +222,10 @@ QDateTime ctkXnatSessionPrivate::updateExpirationDate(qRestResult* restResult)
           }
           QByteArray timeSpan = expirationCookie[1];
           timeSpan.chop(1);
+          this->timeToSessionTimeOutWarning = timeSpan.toLong() - this->timeToSessionTimedOut;
           expirationDate = expirationDate.addMSecs(timeSpan.toLong());
           sessionProperties[SESSION_EXPIRATION_DATE] = expirationDate.toString(Qt::ISODate);
+          this->timer->start(this->timeToSessionTimeOutWarning);
           emit q->sessionRenewed(expirationDate);
         }
       }
@@ -363,6 +375,8 @@ void ctkXnatSession::open()
   QScopedPointer<qRestResult> restResult(d->xnat->takeResult(uuid));
   if (restResult)
   {
+    QObject::connect(d->timer, SIGNAL(timeout()), this, SLOT(emitSessionTimeOut()));
+
     QString sessionId = restResult->result()["content"].toString();
     d->sessionId = sessionId;
     d->setDefaultHttpHeaders();
@@ -514,6 +528,7 @@ QUuid ctkXnatSession::httpGet(const QString& resource, const ctkXnatSession::Url
 {
   Q_D(ctkXnatSession);
   d->checkSession();
+  d->timer->start(d->timeToSessionTimeOutWarning);
   return d->xnat->get(resource, parameters, rawHeaders);
 }
 
@@ -528,6 +543,7 @@ QList<ctkXnatObject*> ctkXnatSession::httpResults(const QUuid& uuid, const QStri
   {
     d->throwXnatException("Http request failed.");
   }
+  d->timer->start(d->timeToSessionTimeOutWarning);
   return d->results(restResult.data(), schemaType);
 }
 
@@ -564,6 +580,7 @@ const QMap<QByteArray, QByteArray> ctkXnatSession::httpHeadSync(const QUuid &uui
 {
   Q_D(ctkXnatSession);
   QScopedPointer<qRestResult> result (d->xnat->takeResult(uuid));
+  d->timer->start(d->timeToSessionTimeOutWarning);
   if (result == NULL)
   {
     d->throwXnatException("Sending HEAD request failed.");
@@ -576,6 +593,7 @@ QUuid ctkXnatSession::httpHead(const QString& resourceUri)
 {
   Q_D(ctkXnatSession);
   QUuid queryId = d->xnat->head(resourceUri);
+  d->timer->start(d->timeToSessionTimeOutWarning);
   return queryId;
 }
 
@@ -597,6 +615,7 @@ void ctkXnatSession::remove(ctkXnatObject* object)
 
   QString query = object->resourceUri();
   bool success = d->xnat->sync(d->xnat->del(query));
+  d->timer->start(d->timeToSessionTimeOutWarning);
 
   if (!success)
   {
@@ -614,6 +633,7 @@ void ctkXnatSession::download(const QString& fileName,
 
   QUuid queryId = d->xnat->download(fileName, resource, parameters, rawHeaders);
   d->xnat->sync(queryId);
+  d->timer->start(d->timeToSessionTimeOutWarning);
 }
 
 //----------------------------------------------------------------------------
@@ -691,3 +711,20 @@ void ctkXnatSession::processResult(QUuid queryId, QList<QVariantMap> parameters)
   Q_UNUSED(queryId)
   Q_UNUSED(parameters)
 }
+
+//----------------------------------------------------------------------------
+void ctkXnatSession::emitSessionTimeOut()
+{
+  Q_D(ctkXnatSession);
+
+  if (d->timer->interval() == d->timeToSessionTimeOutWarning)
+  {
+    d->timer->start(d->timeToSessionTimedOut);
+    emit sessionAboutToBeTimedOut();
+  }
+  else if (d->timer->interval() == d->timeToSessionTimedOut)
+  {
+    d->timer->stop();
+    emit sessionTimedOut();
+  }
+}

+ 11 - 0
Libs/XNAT/Core/ctkXnatSession.h

@@ -272,6 +272,16 @@ public:
 
   Q_SIGNAL void progress(QUuid, double);
 
+  /**
+   * @brief Signals that the session is timed out.
+   */
+  Q_SIGNAL void sessionTimedOut();
+
+  /**
+   * @brief Signals that the session will time out in one minute.
+   */
+  Q_SIGNAL void sessionAboutToBeTimedOut();
+
 public slots:
   void processResult(QUuid queryId, QList<QVariantMap> parameters);
   void onProgress(QUuid queryId, double onProgress);
@@ -282,6 +292,7 @@ protected:
 private:
   Q_DECLARE_PRIVATE(ctkXnatSession)
   Q_DISABLE_COPY(ctkXnatSession)
+  Q_SLOT void emitSessionTimeOut();
 };
 
 #endif