Bonjour à tous et surtout aux spécialistes de la gestion des téléchargements multiples...:magicien:
Mon problème ( un classique...) est le suivant : J'ai créé une classe appelée HistoricManager pouvant gérer la connexion et le download de fichiers XML. Les connaisseurs noteront qu'elle possède les slots classiques connectés aux signaux de QNetworkAccessManager plus des fonctions de parsing DOM XML...
historicmanager.cpp :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 #ifndef HISTORICMANAGER_H #define HISTORICMANAGER_H #include <QObject> #include <QWidget> #include <QNetworkAccessManager> #include <QUrl> #include <QMessageBox> #include <QNetworkReply> #include "historique.h" #include "quandldatadomdoc.h" #include "security.h" class HistoricManager : public QObject { Q_OBJECT private : void forgeURL(const Security & sec); QString getSecurityCode( const Security & sec); public: HistoricManager(); void startRequest(); void connectToProvider(); void sslErrors(QNetworkReply *, const QList<QSslError> &errors); //void slotAuthenticationRequired(QNetworkReply*,QAuthenticator *); void update(const Security & security); QUrl urlToDownload; QNetworkAccessManager qnam; QNetworkReply *reply; QFile *file; int httpGetId; bool httpRequestAborted; QuandlDataDOMDoc *pQuandl; QVector<Historique> Historiques; QMap<QString,QString> ConversionMap; private slots: void startParsing(); void httpFinished(); void httpReadyRead(); void updateDataReadProgress(qint64 bytesRead, qint64 totalBytes); }; #endif // HISTORICMANAGER_H
...Cette classe est instanciée ( une seule fois !) en tant que variable membre d'un objet de type QMainWindow puis , quand cela est nécessaire, celui-ci appelle la méthode update de HistoricManager, ce qui déclenche en cascade le download du fichier dont l'URL est construite à partir de l'objet de type Security passé en paramètre...( via les méthodes forgeURL, puis connectToProvider , puis startrequest...) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210 #include<QDebug> #include"historicmanager.h" #include"security.h" voidHistoricManager::forgeURL(constSecurity&sec) { urlToDownload.setScheme("https"); urlToDownload.setHost("www.yahoo.com"); QStringsecurityPathName=getSecurityCode(sec)+".xml"; urlToDownload.setPath("/api/v3/datasets/YAHOO/"+securityPathName); //On forge la requete ici... urlToDownload.setQuery(requete); } QStringHistoricManager::getSecurityCode(constSecurity&sec) { returnConversionMap[sec.getTicker()]; } HistoricManager::HistoricManager() { for(inti=0;i<listeCorporates.size();i++) { ConversionMap.insert(listeCorporates.at(i),listeCodesYahoo.at(i)); } #ifndefQT_NO_SSL connect(&qnam,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this,SLOT(sslErrors(QNetworkReply*,QList<QSslError>))); #endif } voidHistoricManager::startRequest() { reply=qnam.get(QNetworkRequest(urlToDownload)); connect(reply,SIGNAL(finished()), this,SLOT(httpFinished())); connect(reply,SIGNAL(readyRead()), this,SLOT(httpReadyRead())); connect(reply,SIGNAL(downloadProgress(qint64,qint64)), this,SLOT(updateDataReadProgress(qint64,qint64))); } voidHistoricManager::updateDataReadProgress(qint64bytesRead,qint64totalBytes) { if(httpRequestAborted) return; } voidHistoricManager::connectToProvider() { if(!urlToDownload.isValid()) { qDebug("HistoricManager::connectToProvider:URLinvalide..."); return; } QFileInfofileInfo(urlToDownload.path()); QStringfileName=fileInfo.fileName(); if(fileName.isEmpty()) { qDebug("HistoricManager::connectToProvider:PathNamevide..."); return; } if((QFile::exists(fileName))) { QFileInfolocalFileInfo(fileName); if((localFileInfo.created().date()==QDate::currentDate()) &&(localFileInfo.size()!=0)) { startParsing(); return; } else { QFile::remove(fileName);//Detruitlesfichiersanciensouvideslecaséchéant... } } file=newQFile(fileName); if(!file->open(QIODevice::WriteOnly)) { qDebug("Unabletosavethefile"); deletefile; file=0; return; } //scheduletherequest httpRequestAborted=false; startRequest(); } voidHistoricManager::httpFinished() { if(httpRequestAborted) { if(file){ file->close(); file->remove(); deletefile; file=0; } reply->deleteLater(); return; } file->flush(); file->close(); startParsing(); QVariantredirectionTarget=reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if(reply->error()) { file->remove(); }elseif(!redirectionTarget.isNull()) { QUrlnewUrl=urlToDownload.resolved(redirectionTarget.toUrl()); } reply->deleteLater(); reply=0; deletefile; file=0; } voidHistoricManager::httpReadyRead() { if(file) file->write(reply->readAll()); } #ifndefQT_NO_SSL voidHistoricManager::sslErrors(QNetworkReply*,constQList<QSslError>&errors) { QStringerrorString; foreach(constQSslError&error,errors){ if(!errorString.isEmpty()) errorString+=","; errorString+=error.errorString(); } } #endif voidHistoricManager::update(constSecurity&security) { forgeURL(security); QStringrepr=urlToDownload.toDisplayString(); connectToProvider(); } voidHistoricManager::startParsing() {} <-slot de parsing du fichier XML appelé une fois la download terminé..
...ce qui marche bien pour un seul fichier ( c'est-à-dire quand MaListeDeSecurity ne contient qu'un seul objet ! ).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 foreach(Securitysec,MaListeDeSecurity) { gestionnaireHistoriques->update(sec); }
Le problème survient quand cette fameuse méthode update est appelée plusieurs fois : en effet dès que l'instruction suivante est éxécutée ( dans la méthode startrequest de l'objet HistoricManager ...)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 reply=qnam.get(QNetworkRequest(urlToDownload));
...un thread de connexion est semble-t-il lancé, et le thread principal reprenant la main, la méthode update() se termine, revient à la boucle foreach de l'objet appelant et...réappelle la méthode update() de mon objet HistoricManager qui perd les pédales à ce moment-là ( sans doute a-t-il du mal à gérer plusieurs objets QNetworkAccessManager , QNetworkReply...etc...).
En résumé, j'ai le choix entre :
instancier PLUSIEURS objets HistoricManager dans mon objet principal ( quitte à en faire une liste ) mais cela me paraît un peu lourd et pas très élégant...
ou alors interdire à la fonction update d'être appelée par deux threads différents ( et je n'ai pas de connaissances assez étendues pour le faire ).
Une autre solution de "verrouillage" de l'objet HistoricManager...
Qu'en pensez-vous ?
Partager