ip2cloader.cpp
1 //------------------------------------------------------------------------------
2 // ip2cloader.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2013 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "ip2cloader.h"
24 
25 #include "configuration/doomseekerconfig.h"
26 #include "doomseekerfilepaths.h"
27 #include "ip2c/ip2c.h"
28 #include "ip2c/ip2cparser.h"
29 #include "ip2c/ip2cupdater.h"
30 #include "global.h"
31 #include "log.h"
32 #include <QFile>
33 #include <QTimer>
34 
35 DClass<IP2CLoader>
36 {
37  public:
38  IP2CParser* ip2cParser;
39  IP2CUpdater* ip2cUpdater;
40  bool updateInProgress;
41  bool inFallbackMode;
42 };
43 
44 DPointered(IP2CLoader)
45 
46 IP2CLoader::IP2CLoader(QObject *parent)
48 :QObject(parent)
49 {
50  d->updateInProgress = false;
51  d->inFallbackMode = false;
52 
53  d->ip2cParser = new IP2CParser(IP2C::instance());
54  this->connect(d->ip2cParser, SIGNAL( parsingFinished(bool) ),
55  SLOT( ip2cFinishedParsing(bool) ) );
56 
57  d->ip2cUpdater = new IP2CUpdater();
58  this->connect(d->ip2cUpdater, SIGNAL( databaseDownloadFinished(const QByteArray&) ),
59  SLOT( ip2cFinishUpdate(const QByteArray&) ) );
60  this->connect(d->ip2cUpdater, SIGNAL( downloadProgress(qint64, qint64) ),
61  SIGNAL( downloadProgress(qint64, qint64) ) );
62  this->connect(d->ip2cUpdater, SIGNAL(updateNeeded(int)),
63  SLOT(onUpdateNeeded(int)));
64 }
65 
66 IP2CLoader::~IP2CLoader()
67 {
68  if (d->ip2cParser->isParsing())
69  {
70  gLog << tr("IP2C parser is still working, awaiting stop...");
71  while (d->ip2cParser->isParsing())
72  {
73  Sleep::sleep(1);
74  }
75  }
76 
77  delete d->ip2cParser;
78  delete d->ip2cUpdater;
79 }
80 
81 void IP2CLoader::load()
82 {
83  if (gConfig.doomseeker.bIP2CountryAutoUpdate)
84  d->ip2cUpdater->needsUpdate(DoomseekerFilePaths::ip2cDatabaseAny());
85  ip2cParseDatabase();
86 }
87 
88 void IP2CLoader::onUpdateNeeded(int status)
89 {
90  if (status == IP2CUpdater::UpdateNeeded)
91  {
92  update();
93  }
94  else
95  {
96  switch (status)
97  {
98  case IP2CUpdater::UpToDate:
99  gLog << tr("IP2C update not needed.");
100  break;
101  case IP2CUpdater::UpdateCheckError:
102  gLog << tr("IP2C update errored. See log for details.");
103  break;
104  default:
105  gLog << tr("IP2C update bugged out.");
106  break;
107  }
108  ip2cJobsFinished();
109  }
110 }
111 
112 void IP2CLoader::update()
113 {
114  d->updateInProgress = true;
115  if (!d->ip2cParser->isParsing())
116  {
117  gLog << tr("Starting IP2C update.");
118  IP2C::instance()->setDataAccessLockEnabled(true);
119  d->ip2cUpdater->downloadDatabase(DoomseekerFilePaths::ip2cDatabase());
120  }
121  else
122  {
123  // Delay in hope that parser finishes
124  gLog << tr("IP2C update must wait until parsing of current database finishes. "
125  "Waiting 1 second");
126  QTimer::singleShot(1000, this, SLOT(update()));
127  }
128 }
129 
130 void IP2CLoader::ip2cFinishUpdate(const QByteArray& downloadedData)
131 {
132  d->updateInProgress = false;
133  if (!downloadedData.isEmpty())
134  {
135  gLog << tr("IP2C database finished downloading.");
136  QString filePath = DoomseekerFilePaths::ip2cDatabase();
137  d->ip2cUpdater->getRollbackData(filePath);
138  if (!d->ip2cUpdater->saveDownloadedData(filePath))
139  {
140  gLog << tr("Unable to save IP2C database at path: %1").arg(filePath);
141  }
142  ip2cParseDatabase();
143  }
144  else
145  {
146  gLog << tr("IP2C download has failed.");
147  ip2cJobsFinished();
148  }
149 }
150 
151 void IP2CLoader::ip2cFinishedParsing(bool bSuccess)
152 {
153  QString filePath = DoomseekerFilePaths::ip2cDatabase();
154 
155  if (!bSuccess)
156  {
157  if (d->inFallbackMode)
158  {
159  gLog << tr("Failed to read IP2C fallback. Stopping.");
160  ip2cJobsFinished();
161  return;
162  }
163  gLog << tr("Failed to read IP2C database. Reverting...");
164 
165  d->inFallbackMode = true;
166  if (d->ip2cUpdater == NULL || !d->ip2cUpdater->hasRollbackData())
167  {
168  gLog << tr("IP2C revert attempt failed. Nothing to go back to.");
169 
170  // Delete file in this case.
171  QFile file(filePath);
172  file.remove();
173 
174  QString preinstalledDbPath = DoomseekerFilePaths::ip2cDatabaseAny();
175  if (!preinstalledDbPath.isEmpty())
176  {
177  gLog << tr("Trying to use preinstalled IP2C database.");
178  d->ip2cParser->readDatabaseThreaded(preinstalledDbPath);
179  }
180  else
181  {
182  ip2cJobsFinished();
183  }
184  }
185  else
186  {
187  // Revert to old content.
188  d->ip2cUpdater->rollback(filePath);
189 
190  // Must succeed now.
191  d->ip2cParser->readDatabaseThreaded(filePath);
192  }
193  }
194  else
195  {
196  gLog << tr("IP2C parsing finished.");
197  ip2cJobsFinished();
198  }
199 }
200 
201 void IP2CLoader::ip2cJobsFinished()
202 {
203  if (!d->ip2cUpdater->isWorking() && !d->ip2cParser->isParsing() && !d->updateInProgress)
204  {
205  IP2C::instance()->setDataAccessLockEnabled(false);
206  emit finished();
207  }
208 }
209 
210 void IP2CLoader::ip2cParseDatabase()
211 {
212  QString filePath = DoomseekerFilePaths::ip2cDatabaseAny();
213  if (!filePath.isEmpty())
214  {
215  gLog << tr("Please wait. IP2C database is being read. This may take some time.");
216  // Attempt to read IP2C database.
217 
218  d->inFallbackMode = false;
219  IP2C::instance()->setDataAccessLockEnabled(true);
220  d->ip2cParser->readDatabaseThreaded(filePath);
221  }
222  else
223  {
224  if (!gConfig.doomseeker.bIP2CountryAutoUpdate)
225  {
226  gLog << tr("Did not find any IP2C database. IP2C functionality will be disabled.");
227  gLog << tr("You may install an IP2C database from the \"File\" menu.");
228  }
229  ip2cJobsFinished();
230  }
231 }
IP2CUpdater is responsible for downloading a new version of database from the site.
Definition: ip2cupdater.h:37
static QString ip2cDatabaseAny()
static QString ip2cDatabase()