------------------------------------------------------------ revno: 3294 committer: poy <p...@123gen.com> 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;
_______________________________________________ Mailing list: https://launchpad.net/~linuxdcpp-team Post to : linuxdcpp-team@lists.launchpad.net Unsubscribe : https://launchpad.net/~linuxdcpp-team More help : https://help.launchpad.net/ListHelp