ATLAS Offline Software
VP1AvailEvtsHttps.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3 */
4 
7 #include "VP1Gui/VP1EventFile.h"
8 #include "VP1Gui/VP1MD5Sum.h"
9 #include "VP1Base/VP1Msg.h"
10 
11 #include <QNetworkAccessManager>
12 #include <QNetworkCookie>
13 #include <QFile>
14 #include <QFileInfo>
15 #include <QUrl>
16 #include <QTimer>
17 #include <QBuffer>
18 #include <QStringMatcher>
19 #include <QDateTime>
20 
21 #include <iostream>
22 #include <QMetaType>
23 
24 class QSslError;
25 
26 /*
27  Stage values:
28  0 - get head and check its last_modified header
29  1 - get file info
30  2 - get event file(s)
31  */
32 
34  public:
36  ,QString
37  ,int);
38  ~Imp();
39 
40  void startTimer(int interval=0);
41 
42  // Connect signals of the QNetworkReply to slots of the VP1AvailEvtsHttps
44 
46  QString m_fileInfoUrl;
47  QString m_baseUrl;
49 
50  QNetworkAccessManager* m_netmanager;
51  QNetworkReply* m_netreply;
52  QString m_evtToGet;
53  int m_stage;
54  QString m_urlLastMod;
57  unsigned m_lastChangeTime;
58 
59  QTimer m_stallTimer;
60 };
61 
63  ,QString fileInfoUrl
64  ,int updateInterval)
65  : m_theclass(theclass)
66  , m_fileInfoUrl(fileInfoUrl)
67  , m_baseUrl("")
68  , m_updateInterval(updateInterval)
69  , m_netmanager(0)
70  , m_netreply(0)
71  , m_evtToGet("")
72  , m_stage(0)
73  , m_urlLastMod("UNKNOWN")
74  , m_expectedMD5Sum("")
75  , m_bytesReceived(0)
76  , m_lastChangeTime(0)
77  , m_stallTimer(0)
78 {
79  QUrl url(m_fileInfoUrl);
80  if (url.isValid()) {
81  QString path = url.path();
82  QString infofilebasename = QFileInfo(path).fileName();
83  if (!infofilebasename.isEmpty()&&path.endsWith(infofilebasename)) {
85  m_baseUrl.chop(infofilebasename.count());
86  if (!QUrl(m_baseUrl).isValid())
87  m_baseUrl="";
88  else if (!m_baseUrl.endsWith("/"))
89  m_baseUrl += "/";
90  }
91  }
92 
93  connect(&m_stallTimer,SIGNAL(timeout()), m_theclass, SLOT(checkForStall()));
94  m_stallTimer.start(10000);
95 }
96 
98 {
99 }
100 
102 {
103  QTimer::singleShot((interval>0 ? m_updateInterval : 60) ,m_theclass,SLOT(generateHttpsRequest()));
104 }
105 
107 {
108  connect(m_netreply, SIGNAL(finished()),
109  m_theclass, SLOT(finished()));
110  connect(m_netreply, SIGNAL(error(QNetworkReply::NetworkError)),
111  m_theclass, SLOT(error(QNetworkReply::NetworkError)));
112 #ifndef QT_NO_SSL
113  connect(m_netreply, SIGNAL(sslErrors(const QList<QSslError>&)),
114  m_theclass, SLOT(sslErrors(const QList<QSslError>&)));
115 #endif
116  connect(m_netreply, SIGNAL(downloadProgress(qint64,qint64)),
117  m_theclass, SLOT(dataReadProgress(qint64,qint64)));
118  m_bytesReceived = 0;
119 }
120 
122  int updateInterval,
123  int timeCutForNew,
124  QString tmpcopydir,
126  QObject * parent)
128  , m_d(new Imp(this,fileinfoUrl,updateInterval))
129 {
130 }
131 
133 {
134  delete m_d;
135 }
136 
138 {
139  // Dummy for now
140 }
141 
142 void VP1AvailEvtsHttps::start(QNetworkAccessManager* netmanager)
143 {
144  m_d->m_netmanager = netmanager;
145  m_d->startTimer();
146 }
147 
149 {
150  return m_d->m_fileInfoUrl;
151 }
152 
154 {
155  QUrl fileInfoUrl(m_d->m_fileInfoUrl);
156  QNetworkRequest netrequest(fileInfoUrl);
157  if(m_d->m_stage==0) {
161  m_d->m_netreply = m_d->m_netmanager->head(netrequest);
162  } else if(m_d->m_stage==1) {
166  m_d->m_netreply = m_d->m_netmanager->get(netrequest);
167  } else {
168  // stage 2
173  QString activeRetrievalDir = tmpActiveRetrievalDir();
174  QString target = activeRetrievalDir +"downloadedfileinfo.txt";
175  VP1EvtsOnServerInfo newEvtsOnServerInfo(target);
176 
177  if (!newEvtsOnServerInfo.isValid()) {
178  message("Problems decoding info in file downloaded from " + m_d->m_fileInfoUrl);
181  m_d->m_stage = 0;
183  return;
184  }
185 
186  VP1EventFile evtToGet;
187  QString localfiledir = tmpLocalFileDir();
188 
189  for (VP1EventFile evt : newEvtsOnServerInfo.events(timeCutForNew(),requireNewestRunNumber())) {
190  //We are looking for an event which was never seen before and not available locally:
191  if (!evt.isValid()||inHistory(evt.runNumber(),evt.eventNumber()))
192  continue;
193  if (!QFile::exists(localfiledir+evt.fileName())){
194  evtToGet=evt;
195  break;
196  }
197  }
198 
199  if(evtToGet.isValid()) {
200  //Before we get it, let us check that we don't already have 3
201  //fresh events locally which are newer than the one we are trying
202  //to download:
203  QList<VP1EventFile> freshLocalEvents = freshEvents();
204  unsigned nNewer(0);
205  for(VP1EventFile evt : freshLocalEvents) {
206  if (evt < evtToGet) {
207  ++nNewer;
208  if (nNewer>=3) {
209  m_d->m_stage = 0;
211  return;
212  }
213  }
214  }
215 
216  QUrl url(m_d->m_baseUrl + evtToGet.fileName());
217  m_d->m_expectedMD5Sum = evtToGet.md5Sum();
221  QNetworkRequest netrequestEvt(url);
222  m_d->m_evtToGet = evtToGet.fileName();
223  m_d->m_netreply = m_d->m_netmanager->get(netrequestEvt);
224  } else {
225  m_d->m_stage = 0;
227  return;
228  }
229  }
231 }
232 
234 {
235  VP1Msg::messageDebug("VP1AvailEvtsHttps::finished()");
236  int sc=-9999;
237  QVariant val = m_d->m_netreply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
238  if(val.type()==QVariant::Int)
239  sc = val.value<int>();
240  else if(val.type()==QVariant::Invalid)
241  message("No status code obtained while processing " + m_d->m_netreply->url().toString());
242  else if(!val.canConvert<int>())
243  message("Cannot convert status code to int while processing " + m_d->m_netreply->url().toString());
244  else
245  sc = val.value<int>();
246 
248 
249  QString lastModified;
250  QVariant lastModHeader = m_d->m_netreply->header(QNetworkRequest::LastModifiedHeader);
251  if(lastModHeader.type()!=QVariant::Invalid &&
252  lastModHeader.canConvert<QDateTime>()) {
253  QDateTime lastModTime = lastModHeader.value<QDateTime>();
254  lastModified = lastModTime.toString();
255  }
256 
264  if(m_d->m_netreply->error()==QNetworkReply::NoError) {
265  if(m_d->m_stage==0) {
266  if(!lastModified.isEmpty() && lastModified!=m_d->m_urlLastMod) {
267  // The file info has been modified, go to the stage 1
268  m_d->m_urlLastMod = lastModified;
269  m_d->m_stage = 1;
270  } else {
271  // Reuse the already downloaded file info
272  m_d->m_stage = 2;
273  }
274  }else if(m_d->m_stage==1) {
275  // Write out fileinfo to local file for parsing
276  QString activeRetrievalDir = tmpActiveRetrievalDir();
277  QString target = activeRetrievalDir +"downloadedfileinfo.txt";
283  // Delete already existing fileinfo
284  if(QFileInfo(target).exists() && !QFile(target).remove()) {
285  message("ERROR: Could not remove the old fileinfo " + target);
286  m_d->m_stage = 0;
288  return;
289  }
290 
291  // Create new fileinfo
292  QFile localfileinfo(target);
293  if(!localfileinfo.open(QIODevice::WriteOnly)) {
294  message("ERROR: Unable to open " + target + " for writing");
295  m_d->m_stage = 0;
297  return;
298  }
299 
300  // Wrute received fileinfo to local file
301  QByteArray ba = m_d->m_netreply->readAll();
302  localfileinfo.write(ba);
303  localfileinfo.close();
304  m_d->m_stage = 2;
305  }else if(m_d->m_stage==2) {
306  // Open target file for writing
308  QFile targetFile(target);
309  if(!targetFile.open(QIODevice::WriteOnly)) {
310  message("ERROR: Unable to open " + target + " for writing");
311  m_d->m_stage = 0;
313  return;
314  }
315 
316  // Write to file
317  QByteArray ba = m_d->m_netreply->readAll();
318  targetFile.write(ba);
319  targetFile.close();
324  // Checksum test
326  if(!match) {
327  message("Checksum did not match");
329  m_d->m_stage = 0;
331  return;
332  }
333 
334  QString finalTarget = tmpLocalFileDir()+m_d->m_evtToGet;
335  if(!QFile::rename(target,finalTarget)) {
336  message("ERROR: Could not move " + target + " to " + finalTarget);
338  QFile::remove(finalTarget);
339  } else {
341  }
342 
343  m_d->m_stage = 0;
344  }
345  }
346  else
347  m_d->m_stage = 0;
348 
349  m_d->m_netreply->blockSignals(true);
350  m_d->m_netreply->deleteLater();
351  m_d->m_netreply = 0;
352 
353  int interval = m_d->m_stage>0 ? 0 : m_d->m_updateInterval;
355 }
356 
357 void VP1AvailEvtsHttps::error(QNetworkReply::NetworkError err)
358 {
359  message("Error processing " + m_d->m_netreply->url().toString()
360  + "\n ===> Error code: " + QString::number((int)err)
361  + "\n Error decoding here: http://doc.trolltech.com/4.4/qnetworkreply.html#NetworkError-enum");
362 }
363 
364 #ifndef QT_NO_SSL
365 void VP1AvailEvtsHttps::sslErrors(const QList<QSslError>&)
366 {
373  m_d->m_netreply->ignoreSslErrors();
374 }
375 #endif
376 
377 void VP1AvailEvtsHttps::dataReadProgress(qint64 received, qint64)
378 {
379  if(m_d->m_stage>0) {
380  if(received>m_d->m_bytesReceived) {
381  m_d->m_lastChangeTime = QDateTime::currentDateTime().toTime_t();
382  m_d->m_bytesReceived = received;
383  }
384  } else {
385  m_d->m_lastChangeTime = QDateTime::currentDateTime().toTime_t();
386  }
387 }
388 
390 {
391  unsigned currentTime = QDateTime::currentDateTime().toTime_t();
392  if (currentTime>m_d->m_lastChangeTime+10) {
393  // Abort current download and go to stage 0
394  if(m_d->m_netreply) {
395  m_d->m_netreply->blockSignals(true);
396  delete m_d->m_netreply;
397  m_d->m_netreply=0;
398  m_d->m_stage = 0;
400  }
401  }
402 }
VP1AvailEvtsHttps::generateHttpsRequest
void generateHttpsRequest()
Definition: VP1AvailEvtsHttps.cxx:153
VP1AvailEvents::tmpLocalFileDir
QString tmpLocalFileDir() const
Definition: VP1AvailEvents.cxx:283
VP1AvailEvtsHttps::finished
void finished()
Definition: VP1AvailEvtsHttps.cxx:233
athena.path
path
python interpreter configuration --------------------------------------—
Definition: athena.py:126
VP1AvailEvtsHttps
Definition: VP1AvailEvtsHttps.h:28
VP1AvailEvtsHttps.h
VP1AvailEvtsHttps::init
virtual void init()
Definition: VP1AvailEvtsHttps.cxx:137
VP1EventFile::md5Sum
QString md5Sum() const
Definition: VP1EventFile.cxx:170
VP1Msg.h
fillPileUpNoiseLumi.connect
string connect
Definition: fillPileUpNoiseLumi.py:70
CSV_InDetExporter.new
new
Definition: CSV_InDetExporter.py:145
VP1AvailEvtsHttps::Imp::m_updateInterval
int m_updateInterval
Definition: VP1AvailEvtsHttps.cxx:48
VP1AvailEvents::cleanupAndCheckForEventListChanges
void cleanupAndCheckForEventListChanges()
Definition: VP1AvailEvents.cxx:176
VP1AvailEvents::tmpActiveRetrievalDir
QString tmpActiveRetrievalDir()
Definition: VP1AvailEvents.cxx:277
VP1AvailEvtsHttps::start
void start(QNetworkAccessManager *netmanager)
Definition: VP1AvailEvtsHttps.cxx:142
VP1AvailEvtsHttps::Imp::m_theclass
VP1AvailEvtsHttps * m_theclass
Definition: VP1AvailEvtsHttps.cxx:45
VP1AvailEvtsHttps::Imp::m_fileInfoUrl
QString m_fileInfoUrl
Definition: VP1AvailEvtsHttps.cxx:46
VP1AvailEvtsHttps::Imp::m_netreply
QNetworkReply * m_netreply
Definition: VP1AvailEvtsHttps.cxx:51
VP1AvailEvtsHttps::fileinfoLocation
QString fileinfoLocation()
Definition: VP1AvailEvtsHttps.cxx:148
VP1EventFile::fileName
QString fileName() const
Definition: VP1EventFile.cxx:164
VP1AvailEvtsHttps::checkForStall
void checkForStall()
Definition: VP1AvailEvtsHttps.cxx:389
LArG4FSStartPointFilter.evt
evt
Definition: LArG4FSStartPointFilter.py:42
VP1EvtsOnServerInfo.h
VP1EvtsOnServerInfo
Definition: VP1EvtsOnServerInfo.h:26
isValid
bool isValid(const T &p)
Definition: AtlasPID.h:214
VP1AvailEvtsHttps::Imp::m_baseUrl
QString m_baseUrl
Definition: VP1AvailEvtsHttps.cxx:47
VP1AvailEvtsHttps::VP1AvailEvtsHttps
VP1AvailEvtsHttps(QString fileinfoUrl, int updateInterval, int timeCutForNew, QString tmpcopydir, int maxLocalFilesToKeep=-1, QObject *parent=0)
Definition: VP1AvailEvtsHttps.cxx:121
physics_parameters.url
string url
Definition: physics_parameters.py:27
VP1AvailEvents::message
void message(const QString &) const
AthenaPoolTestRead.sc
sc
Definition: AthenaPoolTestRead.py:27
VP1AvailEvents::inHistory
bool inHistory(int run, int event) const
Definition: VP1AvailEvents.cxx:187
VP1AvailEvents::freshEvents
QList< VP1EventFile > freshEvents() const
Definition: VP1AvailEvents.cxx:129
PixelModuleFeMask_create_db.remove
string remove
Definition: PixelModuleFeMask_create_db.py:83
VP1AvailEvtsHttps::Imp::startTimer
void startTimer(int interval=0)
Definition: VP1AvailEvtsHttps.cxx:101
VP1AvailEvtsHttps::Imp::m_netmanager
QNetworkAccessManager * m_netmanager
Definition: VP1AvailEvtsHttps.cxx:50
dqt_zlumi_pandas.err
err
Definition: dqt_zlumi_pandas.py:193
getLatestRuns.interval
interval
Definition: getLatestRuns.py:24
VP1EventFile.h
VP1AvailEvtsHttps::Imp::connectNetworkSignalsToSlots
void connectNetworkSignalsToSlots()
Definition: VP1AvailEvtsHttps.cxx:106
test_pyathena.parent
parent
Definition: test_pyathena.py:15
VP1AvailEvents::timeCutForNew
int timeCutForNew() const
Definition: VP1AvailEvents.cxx:92
VP1AvailEvtsHttps::Imp
Definition: VP1AvailEvtsHttps.cxx:33
VP1AvailEvtsHttps::Imp::m_bytesReceived
qint64 m_bytesReceived
Definition: VP1AvailEvtsHttps.cxx:56
VP1EventFile::isValid
bool isValid() const
Definition: VP1EventFile.cxx:158
VP1AvailEvtsHttps::Imp::m_evtToGet
QString m_evtToGet
Definition: VP1AvailEvtsHttps.cxx:52
VP1AvailEvents::requireNewestRunNumber
bool requireNewestRunNumber() const
Definition: VP1AvailEvents.h:62
Muon::NoError
@ NoError
Definition: RpcByteStreamErrorContainer.h:31
python.selection.number
number
Definition: selection.py:20
VP1AvailEvtsHttps::dataReadProgress
void dataReadProgress(qint64, qint64)
Definition: VP1AvailEvtsHttps.cxx:377
VP1AvailEvtsHttps::sslErrors
void sslErrors(const QList< QSslError > &)
Definition: VP1AvailEvtsHttps.cxx:365
VP1EvtsOnServerInfo::isValid
bool isValid() const
Definition: VP1EvtsOnServerInfo.cxx:53
VP1AvailEvtsHttps::Imp::m_urlLastMod
QString m_urlLastMod
Definition: VP1AvailEvtsHttps.cxx:54
VP1AvailEvtsHttps::Imp::m_stallTimer
QTimer m_stallTimer
Definition: VP1AvailEvtsHttps.cxx:59
VP1MD5Sum::sumMatches
static bool sumMatches(const QString &filename, const QByteArray &md5sum)
Definition: VP1MD5Sum.cxx:38
VP1AvailEvents::maxLocalFilesToKeep
int maxLocalFilesToKeep() const
Definition: VP1AvailEvents.cxx:98
VP1Msg::messageDebug
static void messageDebug(const QString &)
Definition: VP1Msg.cxx:39
VP1AvailEvtsHttps::error
void error(QNetworkReply::NetworkError)
Definition: VP1AvailEvtsHttps.cxx:357
VP1EventFile
Definition: VP1EventFile.h:23
Pythia8_RapidityOrderMPI.val
val
Definition: Pythia8_RapidityOrderMPI.py:14
VP1AvailEvtsHttps::Imp::m_expectedMD5Sum
QString m_expectedMD5Sum
Definition: VP1AvailEvtsHttps.cxx:55
VP1AvailEvtsHttps::Imp::m_stage
int m_stage
Definition: VP1AvailEvtsHttps.cxx:53
VP1AvailEvtsHttps::Imp::Imp
Imp(VP1AvailEvtsHttps *, QString, int)
Definition: VP1AvailEvtsHttps.cxx:62
VP1MD5Sum.h
VP1AvailEvents
Definition: VP1AvailEvents.h:25
VP1AvailEvtsHttps::m_d
Imp * m_d
Definition: VP1AvailEvtsHttps.h:63
COOLRates.target
target
Definition: COOLRates.py:1106
python.dummyaccess.exists
def exists(filename)
Definition: dummyaccess.py:9
VP1AvailEvtsHttps::Imp::~Imp
~Imp()
Definition: VP1AvailEvtsHttps.cxx:97
python.TrigInDetArtSteps.timeout
timeout
Definition: TrigInDetArtSteps.py:35
VP1EvtsOnServerInfo::events
QList< VP1EventFile > events(int timecut=-1, bool requireNewestRunNumber=false) const
Definition: VP1EvtsOnServerInfo.cxx:241
VP1AvailEvtsHttps::~VP1AvailEvtsHttps
virtual ~VP1AvailEvtsHttps()
Definition: VP1AvailEvtsHttps.cxx:132
VP1AvailEvents::invalidateDirCache
void invalidateDirCache(const QString &dir)
Definition: VP1AvailEvents.cxx:194
match
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition: hcg.cxx:356
VP1AvailEvtsHttps::Imp::m_lastChangeTime
unsigned m_lastChangeTime
Definition: VP1AvailEvtsHttps.cxx:57