linuxdcpp-team team mailing list archive
-
linuxdcpp-team team
-
Mailing list archive
-
Message #06865
[Branch ~dcplusplus-team/dcplusplus/trunk] Rev 3294: dl the geoip region db; refresh geoip caches in their socket thread
------------------------------------------------------------
revno: 3294
committer: poy <poy@xxxxxxxxxx>
branch nick: trunk
timestamp: Wed 2013-05-15 01:30:49 +0200
message:
dl the geoip region db; refresh geoip caches in their socket thread
modified:
dcpp/GeoIP.cpp
dcpp/GeoManager.cpp
dcpp/GeoManager.h
win32/MainWindow.cpp
win32/MainWindow.h
--
lp:dcplusplus
https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk
Your team Dcplusplus-team is subscribed to branch lp:dcplusplus.
To unsubscribe from this branch go to https://code.launchpad.net/~dcplusplus-team/dcplusplus/trunk/+edit-subscription
=== modified file 'dcpp/GeoIP.cpp'
--- dcpp/GeoIP.cpp 2013-05-13 18:38:30 +0000
+++ dcpp/GeoIP.cpp 2013-05-14 23:30:49 +0000
@@ -21,6 +21,7 @@
#include "File.h"
#include "format.h"
+#include "GeoManager.h"
#include "SettingsManager.h"
#include "Util.h"
#include "ZUtils.h"
@@ -140,6 +141,42 @@
#endif
}
+inline uint32_t regionCode(char country0, char country1, char region0, char region1) {
+ union { char chars[4]; uint32_t i; } u = { country0, country1, region0, region1 };
+ return u.i;
+}
+
+unordered_map<uint32_t, string> getRegions() {
+ unordered_map<uint32_t, string> ret;
+ if(!SETTING(GEO_REGION))
+ return ret;
+ if(SETTING(COUNTRY_FORMAT).find("%[region]") == string::npos)
+ return ret;
+ try {
+ auto regions = File(GeoManager::getRegionDbPath(), File::READ, File::OPEN).read();
+ size_t begin = 0, end;
+ while((end = regions.find('\n', begin)) != string::npos) {
+ if(begin + 9 > end) { break; } // corrupted file
+ auto country0 = regions[begin++];
+ auto country1 = regions[begin++];
+ ++begin; // comma
+ auto region0 = regions[begin++];
+ auto region1 = regions[begin++];
+ ++begin; // comma
+ ++begin; // begin quote
+ --end; // end quote
+ ret[regionCode(country0, country1, region0, region1)] = regions.substr(begin, end - begin);
+ begin = end + 2; // end quote + new line
+ }
+ } catch (const FileException&) { }
+ return ret;
+}
+
+string regionName(const unordered_map<uint32_t, string>& regions, const char* country, const char* region) {
+ auto i = regions.find(regionCode(country[0], country[1], region[0], region[1]));
+ return i != regions.cend() ? i->second : string();
+}
+
} // unnamed namespace
void GeoIP::rebuild_cities() {
@@ -147,6 +184,8 @@
const auto& setting = SETTING(COUNTRY_FORMAT);
+ const auto regions = getRegions();
+
GeoIPRecord* record = nullptr;
auto id = GeoIP_init_record_iter(geo);
auto prev_id = id;
@@ -161,11 +200,11 @@
params["long"] = [record] { return Util::toString(record->longitude); };
params["metrocode"] = [record] { return Util::toString(record->metro_code); };
params["postcode"] = [record] { return forwardRet(record->postal_code); };
- params["region"] = [record]() -> string {
+ params["region"] = [record, ®ions]() -> string {
auto country = GeoIP_code_by_id(record->country);
auto region = record->region;
if(country && region) {
- // todo
+ return regionName(regions, country, region);
}
return forwardRet(region);
};
=== modified file 'dcpp/GeoManager.cpp'
--- dcpp/GeoManager.cpp 2013-01-18 21:28:38 +0000
+++ dcpp/GeoManager.cpp 2013-05-14 23:30:49 +0000
@@ -70,4 +70,8 @@
return Util::getPath(Util::PATH_USER_LOCAL) + (v6 ? "GeoIPv6.dat" : "GeoIP.dat");
}
+string GeoManager::getRegionDbPath() {
+ return Util::getPath(Util::PATH_USER_LOCAL) + "GeoIP_Regions.csv";
+}
+
} // namespace dcpp
=== modified file 'dcpp/GeoManager.h'
--- dcpp/GeoManager.h 2013-04-16 16:11:50 +0000
+++ dcpp/GeoManager.h 2013-05-14 23:30:49 +0000
@@ -49,6 +49,7 @@
const string& getCountry(const string& ip, int flags = V6 | V4);
static string getDbPath(bool v6);
+ static string getRegionDbPath();
private:
friend class Singleton<GeoManager>;
=== modified file 'win32/MainWindow.cpp'
--- win32/MainWindow.cpp 2013-05-13 18:22:52 +0000
+++ win32/MainWindow.cpp 2013-05-14 23:30:49 +0000
@@ -104,6 +104,7 @@
toolbar(0),
tabs(0),
tray_pm(false),
+geoRegion(GeoRegion_Idle),
stopperThread(NULL),
lastUp(0),
lastDown(0),
@@ -119,6 +120,7 @@
links.geoip4 = _T("http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz");
links.geoip6_city = _T("http://geolite.maxmind.com/download/geoip/database/GeoLiteCityv6-beta/GeoLiteCityv6.dat.gz");
links.geoip4_city = _T("http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz");
+ links.geoip_regions = _T("http://dev.maxmind.com/static/csv/codes/maxmind/region.csv");
links.faq = links.homepage + _T("faq/");
links.help = links.homepage + _T("help/");
links.discuss = links.homepage + _T("discussion/");
@@ -678,8 +680,6 @@
auto i = commands.find(text);
if(i == commands.end()) { return; }
-
- auto index = std::distance(commands.begin(), i);
commands.erase(i);
if(commands.empty()) {
@@ -843,7 +843,7 @@
void MainWindow::handlePlugins(const dwt::ScreenCoordinate& pt) {
auto menu = addChild(WinUtil::Seeds::menu);
- menu->setTitle(T_("Plugins"));
+ menu->setTitle(T_("Plugins"), WinUtil::menuIcon(IDI_PLUGINS));
addPluginCommands(menu.get());
menu->open(pt);
@@ -1227,6 +1227,7 @@
auto prevGeo = SETTING(GET_USER_COUNTRY);
auto prevGeoCity = SETTING(GEO_CITY);
+ auto prevGeoRegion = SETTING(GEO_REGION);
auto prevGeoFormat = SETTING(COUNTRY_FORMAT);
auto prevFont = SETTING(MAIN_FONT);
@@ -1259,10 +1260,10 @@
ClientManager::getInstance()->infoUpdated();
bool rebuildGeo = prevGeo && SETTING(COUNTRY_FORMAT) != prevGeoFormat;
- if(SETTING(GET_USER_COUNTRY) != prevGeo || SETTING(GEO_CITY) != prevGeoCity) {
+ if(SETTING(GET_USER_COUNTRY) != prevGeo || SETTING(GEO_CITY) != prevGeoCity || SETTING(GEO_REGION) != prevGeoRegion) {
if(SETTING(GET_USER_COUNTRY)) {
GeoManager::getInstance()->init();
- if(SETTING(GEO_CITY) != prevGeoCity) {
+ if(SETTING(GEO_CITY) != prevGeoCity || (SETTING(GEO_CITY) && SETTING(GEO_REGION) != prevGeoRegion)) {
updateGeo();
} else {
checkGeoUpdate();
@@ -1478,6 +1479,10 @@
links.geoip4_city = Text::toT(xml.getChildData());
}
xml.resetCurrentChild();
+ if(xml.findChild("GeoIP_Regions")) {
+ links.geoip_regions = Text::toT(xml.getChildData());
+ }
+ xml.resetCurrentChild();
if(xml.findChild("Faq")) {
links.faq = Text::toT(xml.getChildData());
}
@@ -1564,7 +1569,7 @@
void MainWindow::updateGeo(bool v6) {
auto& conn = conns[v6 ? CONN_GEO_V6 : CONN_GEO_V4];
- if(conn)
+ if(static_cast<HttpConnection*>(conn))
return;
auto& file = v6 ? geo6File : geo4File;
@@ -1581,10 +1586,56 @@
}
void MainWindow::completeGeoUpdate(bool v6, bool success) {
+ /* careful, no GUI call here! this runs in the socket thread so as not to freeze the GUI while
+ regenerating GeoIP caches. */
+
if(success) {
+
+ /* this is tricky: the region file covers both v6 & v4 databases so we try our best to
+ download it only once. both databases are refreshed after a succesful region download. */
+ if(SETTING(GEO_CITY) && SETTING(GEO_REGION)) {
+
+ if(geoRegion == (v6 ? GeoRegion_FromV6 : GeoRegion_FromV4)) {
+ geoRegion = GeoRegion_Idle;
+
+ try {
+ File::renameFile(GeoManager::getRegionDbPath() + ".tmp", GeoManager::getRegionDbPath());
+ } catch(const FileException&) { }
+
+ GeoManager::getInstance()->update(true);
+ LogManager::getInstance()->message(str(F_("The %1% GeoIP database has been successfully updated") % geoType(true)));
+ GeoManager::getInstance()->update(false);
+ LogManager::getInstance()->message(str(F_("The %1% GeoIP database has been successfully updated") % geoType(false)));
+
+ } else if(geoRegion == GeoRegion_Idle) {
+
+ /* do nothing if the other download is running - regions will be downloaded and
+ both databases will be refreshed once it completes. */
+ if(static_cast<HttpConnection*>(conns[v6 ? CONN_GEO_V4 : CONN_GEO_V6]))
+ return;
+
+ geoRegion = v6 ? GeoRegion_FromV6 : GeoRegion_FromV4;
+ auto& file = v6 ? geo6File : geo4File;
+ try {
+ file.reset(new File(GeoManager::getRegionDbPath() + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE));
+ conns[v6 ? CONN_GEO_V6 : CONN_GEO_V4] = HttpManager::getInstance()->download(Text::fromT(links.geoip_regions), file.get());
+ } catch(const FileException&) {
+ geoRegion = GeoRegion_Idle;
+ }
+ }
+
+ return;
+ }
+
GeoManager::getInstance()->update(v6);
+
LogManager::getInstance()->message(str(F_("The %1% GeoIP database has been successfully updated") % geoType(v6)));
+
} else {
+ if(geoRegion == (v6 ? GeoRegion_FromV6 : GeoRegion_FromV4)) {
+ geoRegion = GeoRegion_Idle;
+ }
+
LogManager::getInstance()->message(str(F_("The %1% GeoIP database could not be updated") % geoType(v6)));
}
}
@@ -1837,13 +1888,13 @@
conns[CONN_GEO_V6] = nullptr;
geo6File.reset();
- callAsync([this] { completeGeoUpdate(true, false); });
+ completeGeoUpdate(true, false);
} else if(c == conns[CONN_GEO_V4]) {
conns[CONN_GEO_V4] = nullptr;
geo4File.reset();
- callAsync([this] { completeGeoUpdate(false, false); });
+ completeGeoUpdate(false, false);
}
}
@@ -1858,13 +1909,13 @@
conns[CONN_GEO_V6] = nullptr;
geo6File.reset();
- callAsync([this] { completeGeoUpdate(true, true); });
+ completeGeoUpdate(true, true);
} else if(c == conns[CONN_GEO_V4]) {
conns[CONN_GEO_V4] = nullptr;
geo4File.reset();
- callAsync([this] { completeGeoUpdate(false, true); });
+ completeGeoUpdate(false, true);
}
}
=== modified file 'win32/MainWindow.h'
--- win32/MainWindow.h 2013-05-13 18:22:52 +0000
+++ win32/MainWindow.h 2013-05-14 23:30:49 +0000
@@ -20,6 +20,7 @@
#define DCPLUSPLUS_WIN32_MAIN_WINDOW_H
#include <dcpp/forward.h>
+#include <dcpp/atomic.h>
#include <dcpp/HttpManagerListener.h>
#include <dcpp/LogManagerListener.h>
#include <dcpp/QueueManagerListener.h>
@@ -100,6 +101,7 @@
tstring geoip4;
tstring geoip6_city;
tstring geoip4_city;
+ tstring geoip_regions;
tstring faq;
tstring help;
tstring discuss;
@@ -142,8 +144,9 @@
plugin GUID -> { command name -> pair<callback, icon path> } */
static unordered_map<string, map<tstring, pair<function<void ()>, tstring>, noCaseStringLess>> pluginCommands;
- HttpConnection* conns[CONN_LAST];
+ atomic<HttpConnection*> conns[CONN_LAST];
unique_ptr<File> geo6File, geo4File;
+ enum { GeoRegion_Idle, GeoRegion_FromV4, GeoRegion_FromV6 } geoRegion;
HANDLE stopperThread;