Core/Realms: Made realmlist threadsafe

This commit is contained in:
Shauren
2017-10-11 22:42:03 +02:00
parent b09bd8d702
commit 644af37f96
2 changed files with 66 additions and 46 deletions

View File

@@ -29,10 +29,13 @@
#include "RealmList.pb.h"
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <zlib.h>
RealmList::RealmList() : _updateInterval(0)
{
_realmsMutex = Trinity::make_unique<boost::shared_mutex>();
}
RealmList::~RealmList()
@@ -61,14 +64,11 @@ void RealmList::Close()
_updateTimer->cancel();
}
void RealmList::UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
void RealmList::UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
boost::asio::ip::address const& address, boost::asio::ip::address const& localAddr, boost::asio::ip::address const& localSubmask,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel,
float population)
{
// Create new if not exist or update existed
Realm& realm = _realms[id];
realm.Id = id;
realm.Build = build;
if (realm.Name != name)
@@ -101,7 +101,8 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
for (auto const& p : _realms)
existingRealms[p.first] = p.second.Name;
_realms.clear();
std::unordered_set<std::string> newSubRegions;
RealmMap newRealms;
// Circle through results and add them to the realm map
if (result)
@@ -163,10 +164,10 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
Battlenet::RealmHandle id{ region, battlegroup, realmId };
UpdateRealm(id, build, name, externalAddress, localAddress, localSubmask, port, icon, flag,
timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
UpdateRealm(newRealms[id], id, build, name, externalAddress, localAddress, localSubmask, port, icon,
flag, timezone, (allowedSecurityLevel <= SEC_ADMINISTRATOR ? AccountTypes(allowedSecurityLevel) : SEC_ADMINISTRATOR), pop);
_subRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString());
newSubRegions.insert(Battlenet::RealmHandle{ region, battlegroup, 0 }.GetAddressString());
if (!existingRealms.count(id))
TC_LOG_INFO("realmlist", "Added realm \"%s\" at %s:%u.", name.c_str(), externalAddress.to_string().c_str(), port);
@@ -187,6 +188,13 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
for (auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr)
TC_LOG_INFO("realmlist", "Removed realm \"%s\".", itr->second.c_str());
{
std::unique_lock<boost::shared_mutex> lock(*_realmsMutex);
_subRegions.swap(newSubRegions);
_realms.swap(newRealms);
}
if (_updateInterval)
{
_updateTimer->expires_from_now(boost::posix_time::seconds(_updateInterval));
@@ -196,6 +204,7 @@ void RealmList::UpdateRealms(boost::system::error_code const& error)
Realm const* RealmList::GetRealm(Battlenet::RealmHandle const& id) const
{
boost::shared_lock<boost::shared_mutex> lock(*_realmsMutex);
auto itr = _realms.find(id);
if (itr != _realms.end())
return &itr->second;
@@ -237,13 +246,15 @@ RealmBuildInfo const* RealmList::GetBuildInfo(uint32 build) const
void RealmList::WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const
{
for (std::string const& subRegion : GetSubRegions())
boost::shared_lock<boost::shared_mutex> lock(*_realmsMutex);
for (std::string const& subRegion : _subRegions)
response->add_attribute_value()->set_string_value(subRegion);
}
std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const
{
std::vector<uint8> compressed;
boost::shared_lock<boost::shared_mutex> lock(*_realmsMutex);
if (Realm const* realm = GetRealm(id))
{
if (!(realm->Flags & REALM_FLAG_OFFLINE) && realm->Build == build)
@@ -276,6 +287,8 @@ std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id
realmEntry.set_cfgconfigsid(realm->GetConfigId());
realmEntry.set_cfglanguagesid(1);
lock.unlock();
std::string json = "JamJSONRealmEntry:" + JSON::Serialize(realmEntry);
uLong compressedLength = compressBound(uLong(json.length()));
@@ -295,44 +308,47 @@ std::vector<uint8> RealmList::GetRealmEntryJSON(Battlenet::RealmHandle const& id
std::vector<uint8> RealmList::GetRealmList(uint32 build, std::string const& subRegion) const
{
JSON::RealmList::RealmListUpdates realmList;
for (auto const& realm : _realms)
{
if (realm.second.Id.GetSubRegionAddress() != subRegion)
continue;
uint32 flag = realm.second.Flags;
if (realm.second.Build != build)
flag |= REALM_FLAG_VERSION_MISMATCH;
JSON::RealmList::RealmState* state = realmList.add_updates();
state->mutable_update()->set_wowrealmaddress(realm.second.Id.GetAddress());
state->mutable_update()->set_cfgtimezonesid(1);
state->mutable_update()->set_populationstate((realm.second.Flags & REALM_FLAG_OFFLINE) ? 0u : std::max(uint32(realm.second.PopulationLevel), 1u));
state->mutable_update()->set_cfgcategoriesid(realm.second.Timezone);
JSON::RealmList::ClientVersion* version = state->mutable_update()->mutable_version();
if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.second.Build))
boost::shared_lock<boost::shared_mutex> lock(*_realmsMutex);
for (auto const& realm : _realms)
{
version->set_versionmajor(buildInfo->MajorVersion);
version->set_versionminor(buildInfo->MinorVersion);
version->set_versionrevision(buildInfo->BugfixVersion);
version->set_versionbuild(buildInfo->Build);
}
else
{
version->set_versionmajor(6);
version->set_versionminor(2);
version->set_versionrevision(4);
version->set_versionbuild(realm.second.Build);
}
if (realm.second.Id.GetSubRegionAddress() != subRegion)
continue;
state->mutable_update()->set_cfgrealmsid(realm.second.Id.Realm);
state->mutable_update()->set_flags(flag);
state->mutable_update()->set_name(realm.second.Name);
state->mutable_update()->set_cfgconfigsid(realm.second.GetConfigId());
state->mutable_update()->set_cfglanguagesid(1);
uint32 flag = realm.second.Flags;
if (realm.second.Build != build)
flag |= REALM_FLAG_VERSION_MISMATCH;
state->set_deleting(false);
JSON::RealmList::RealmState* state = realmList.add_updates();
state->mutable_update()->set_wowrealmaddress(realm.second.Id.GetAddress());
state->mutable_update()->set_cfgtimezonesid(1);
state->mutable_update()->set_populationstate((realm.second.Flags & REALM_FLAG_OFFLINE) ? 0u : std::max(uint32(realm.second.PopulationLevel), 1u));
state->mutable_update()->set_cfgcategoriesid(realm.second.Timezone);
JSON::RealmList::ClientVersion* version = state->mutable_update()->mutable_version();
if (RealmBuildInfo const* buildInfo = GetBuildInfo(realm.second.Build))
{
version->set_versionmajor(buildInfo->MajorVersion);
version->set_versionminor(buildInfo->MinorVersion);
version->set_versionrevision(buildInfo->BugfixVersion);
version->set_versionbuild(buildInfo->Build);
}
else
{
version->set_versionmajor(6);
version->set_versionminor(2);
version->set_versionrevision(4);
version->set_versionbuild(realm.second.Build);
}
state->mutable_update()->set_cfgrealmsid(realm.second.Id.Realm);
state->mutable_update()->set_flags(flag);
state->mutable_update()->set_name(realm.second.Name);
state->mutable_update()->set_cfgconfigsid(realm.second.GetConfigId());
state->mutable_update()->set_cfglanguagesid(1);
state->set_deleting(false);
}
}
std::string json = "JSONRealmListUpdates:" + JSON::Serialize(realmList);
@@ -352,6 +368,7 @@ std::vector<uint8> RealmList::GetRealmList(uint32 build, std::string const& subR
uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret,
LocaleConstant locale, std::string const& os, std::string accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const
{
boost::shared_lock<boost::shared_mutex> lock(*_realmsMutex);
if (Realm const* realm = GetRealm(Battlenet::RealmHandle(realmAddress)))
{
if (realm->Flags & REALM_FLAG_OFFLINE || realm->Build != build)
@@ -365,6 +382,8 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::
address->set_ip(realm->GetAddressForClient(clientAddress).to_string());
address->set_port(realm->Port);
lock.unlock();
std::string json = "JSONRealmListServerIPAddresses:" + JSON::Serialize(serverAddresses);
uLong compressedLength = compressBound(uLong(json.length()));

View File

@@ -36,6 +36,8 @@ struct RealmBuildInfo
namespace boost
{
class shared_mutex;
namespace asio
{
class io_service;
@@ -83,11 +85,9 @@ public:
void Initialize(boost::asio::io_service& ioService, uint32 updateInterval);
void Close();
RealmMap const& GetRealms() const { return _realms; }
Realm const* GetRealm(Battlenet::RealmHandle const& id) const;
RealmBuildInfo const* GetBuildInfo(uint32 build) const;
std::unordered_set<std::string> const& GetSubRegions() const { return _subRegions; }
void WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse* response) const;
std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const;
std::vector<uint8> GetRealmList(uint32 build, std::string const& subRegion) const;
@@ -98,10 +98,11 @@ private:
RealmList();
void UpdateRealms(boost::system::error_code const& error);
void UpdateRealm(Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
void UpdateRealm(Realm& realm, Battlenet::RealmHandle const& id, uint32 build, std::string const& name,
boost::asio::ip::address const& address, boost::asio::ip::address const& localAddr, boost::asio::ip::address const& localSubmask,
uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, float population);
std::unique_ptr<boost::shared_mutex> _realmsMutex;
RealmMap _realms;
std::unordered_set<std::string> _subRegions;
uint32 _updateInterval;