ATLAS Offline Software
Loading...
Searching...
No Matches
VP1AvailEvtsHttps.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
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
24class 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
47 QString m_baseUrl;
49
50 QNetworkAccessManager* m_netmanager;
51 QNetworkReply* m_netreply;
52 QString m_evtToGet;
54 QString m_urlLastMod;
58
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")
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
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
121VP1AvailEvtsHttps::VP1AvailEvtsHttps(const QString & fileinfoUrl,
122 int updateInterval,
123 int timeCutForNew,
124 const QString& tmpcopydir,
126 QObject * parent)
128 , m_d(new Imp(this,fileinfoUrl,updateInterval))
129{
130}
131
136
138{
139 // Dummy for now
140}
141
142void 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
172
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);
179 QFile::remove(target);
181 m_d->m_stage = 0;
182 m_d->startTimer(m_d->m_updateInterval);
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;
210 m_d->startTimer(m_d->m_updateInterval);
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;
226 m_d->startTimer(m_d->m_updateInterval);
227 return;
228 }
229 }
230 m_d->connectNetworkSignalsToSlots();
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
247 VP1Msg::messageDebug("sc: " + QString::number(sc));
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
263
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 = std::move(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";
282
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;
287 m_d->startTimer(m_d->m_updateInterval);
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;
296 m_d->startTimer(m_d->m_updateInterval);
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
307 QString target = tmpActiveRetrievalDir() + m_d->m_evtToGet;
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;
312 m_d->startTimer(m_d->m_updateInterval);
313 return;
314 }
315
316 // Write to file
317 QByteArray ba = m_d->m_netreply->readAll();
318 targetFile.write(ba);
319 targetFile.close();
323
324 // Checksum test
325 bool match = VP1MD5Sum::sumMatches(target,m_d->m_expectedMD5Sum);
326 if(!match) {
327 message("Checksum did not match");
328 QFile::remove(target);
329 m_d->m_stage = 0;
330 m_d->startTimer(m_d->m_updateInterval);
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);
337 QFile::remove(target);
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;
354 m_d->startTimer(interval);
355}
356
357void 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
365void VP1AvailEvtsHttps::sslErrors(const QList<QSslError>&)
366{
373 m_d->m_netreply->ignoreSslErrors();
374}
375#endif
376
377void 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;
399 m_d->startTimer(m_d->m_updateInterval);
400 }
401 }
402}
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
static Double_t sc
QList< VP1EventFile > freshEvents() const
QString tmpLocalFileDir() const
void message(const QString &) const
VP1AvailEvents(int timeCutForNew, const QString &tmpdir, int maxLocalFilesToKeep=-1, QObject *parent=0)
bool requireNewestRunNumber() const
int timeCutForNew() const
bool inHistory(int run, int event) const
int maxLocalFilesToKeep() const
void invalidateDirCache(const QString &dir)
void cleanupAndCheckForEventListChanges()
QString tmpActiveRetrievalDir()
QNetworkAccessManager * m_netmanager
void startTimer(int interval=0)
VP1AvailEvtsHttps * m_theclass
Imp(VP1AvailEvtsHttps *, QString, int)
void error(QNetworkReply::NetworkError)
const QString & fileinfoLocation()
VP1AvailEvtsHttps(const QString &fileinfoUrl, int updateInterval, int timeCutForNew, const QString &tmpcopydir, int maxLocalFilesToKeep=-1, QObject *parent=0)
void sslErrors(const QList< QSslError > &)
void dataReadProgress(qint64, qint64)
void start(QNetworkAccessManager *netmanager)
const QString & fileName() const
bool isValid() const
const QString & md5Sum() const
QList< VP1EventFile > events(int timecut=-1, bool requireNewestRunNumber=false) const
static bool sumMatches(const QString &filename, const QByteArray &md5sum)
Definition VP1MD5Sum.cxx:38
static void messageDebug(const QString &)
Definition VP1Msg.cxx:39
bool exists(const std::string &filename)
does a file exist
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357