31#include <boost/asio/ip/tcp.hpp>
36bool CompressJson(std::string
const& json, std::vector<uint8>* compressed)
38 uLong uncompressedLength = uLong(json.length() + 1);
39 uLong compressedLength = compressBound(uLong(json.length()));
40 compressed->resize(compressedLength + 4);
41 memcpy(compressed->data(), &uncompressedLength,
sizeof(uncompressedLength));
43 if (compress(compressed->data() + 4, &compressedLength,
reinterpret_cast<uint8 const*
>(json.data()), uncompressedLength) != Z_OK)
49 compressed->resize(compressedLength + 4);
70 _updateTimer = std::make_unique<Trinity::Asio::DeadlineTimer>(ioContext);
71 _resolver = std::make_unique<Trinity::Net::Resolver>(ioContext);
84 std::vector<boost::asio::ip::address>&& addresses,
90 if (realm.
Name != name)
108 std::map<Battlenet::RealmHandle, std::string> existingRealms;
110 existingRealms[p.first] = p.second->Name;
112 std::unordered_set<std::string> newSubRegions;
120 Field* fields = result->Fetch();
122 std::string name = fields[1].
GetString();
123 std::vector<boost::asio::ip::address> addresses;
125 for (std::size_t i = 0; i < 4; ++i)
129 for (boost::asio::ip::tcp::endpoint
const& endpoint :
_resolver->ResolveAll(*addressStr,
""))
131 boost::asio::ip::address address = endpoint.address();
135 addresses.push_back(std::move(address));
140 if (addresses.empty())
142 TC_LOG_ERROR(
"realmlist",
"Could not resolve any address for realm \"{}\" id {}", name, realmId);
162 UpdateRealm(*newRealms.try_emplace(
id, std::make_shared<Realm>()).first->second,
id, build, name, std::move(addresses), port, icon,
167 auto buildAddressesLogText = [&]
170 for (boost::asio::ip::address
const& address : newRealms[id]->Addresses)
172 text += address.to_string();
178 if (!existingRealms.erase(
id))
179 TC_LOG_INFO(
"realmlist",
"Added realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port);
181 TC_LOG_DEBUG(
"realmlist",
"Updating realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port);
183 while (result->NextRow());
186 for (
auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr)
187 TC_LOG_INFO(
"realmlist",
"Removed realm \"{}\".", itr->second);
204 _updateTimer->async_wait([
this](boost::system::error_code
const& error)
272 if (realm.
Build != clientBuild)
284 std::vector<uint8> compressed;
285 if (std::shared_ptr<Realm const> realm =
GetRealm(
id))
293 CompressJson(json, &compressed);
305 for (
auto const& [_, realm] :
_realms)
307 if (realm->Id.GetSubRegionAddress() != subRegion)
317 if (
id.GetSubRegionAddress() != subRegion)
326 std::string json =
"JSONRealmListUpdates:" +
JSON::Serialize(realmList);
327 std::vector<uint8> compressed;
328 CompressJson(json, &compressed);
333 std::array<uint8, 32>
const& clientSecret,
LocaleConstant locale, std::string
const& os,
Minutes timezoneOffset, std::string
const& accountName,
336 if (std::shared_ptr<Realm const> realm =
GetRealm(realmAddress))
341 boost::asio::ip::address addressForClient = realm->GetAddressForClient(clientAddress);
345 addressFamily->
set_family(addressForClient.is_v6() ? 2 : 1);
348 address->
set_ip(addressForClient.to_string());
351 std::string json =
"JSONRealmListServerIPAddresses:" +
JSON::Serialize(serverAddresses);
352 std::vector<uint8> compressed;
354 if (!CompressJson(json, &compressed))
357 std::array<uint8, 32> serverSecret = Trinity::Crypto::GetRandomBytes<32>();
359 std::array<uint8, 64> keyData;
360 auto keyDestItr = keyData.begin();
361 keyDestItr = std::ranges::copy(clientSecret, keyDestItr).out;
362 keyDestItr = std::ranges::copy(serverSecret, keyDestItr).out;
366 stmt->
setString(1, clientAddress.to_string());
370 stmt->
setInt16(5, timezoneOffset.count());
381 attribute->
set_name(
"Param_RealmJoinTicket");
385 attribute->
set_name(
"Param_ServerAddresses");
389 attribute->
set_name(
"Param_JoinSecret");
@ ERROR_UTIL_SERVER_FAILED_TO_SERIALIZE_RESPONSE
@ ERROR_USER_SERVER_NOT_PERMITTED_ON_REALM
@ ERROR_UTIL_SERVER_UNKNOWN_REALM
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
std::chrono::minutes Minutes
Minutes shorthand typedef.
#define TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_INFO(filterType__, message__,...)
@ LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO
std::optional< T > Optional
Optional helper class to wrap optional values within.
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Class used to access individual fields of database query result.
uint32 GetUInt32() const noexcept
uint16 GetUInt16() const noexcept
uint8 GetUInt8() const noexcept
std::string GetString() const noexcept
void set_versionminor(::google::protobuf::uint32 value)
void set_versionmajor(::google::protobuf::uint32 value)
void set_versionrevision(::google::protobuf::uint32 value)
void set_versionbuild(::google::protobuf::uint32 value)
void set_port(::google::protobuf::uint32 value)
void set_ip(const ::std::string &value)
inline ::JSON::RealmList::ClientVersion * mutable_version()
void set_populationstate(::google::protobuf::uint32 value)
void set_wowrealmaddress(::google::protobuf::uint32 value)
void set_cfgrealmsid(::google::protobuf::uint32 value)
void set_name(const ::std::string &value)
void set_flags(::google::protobuf::uint32 value)
void set_cfgcategoriesid(::google::protobuf::uint32 value)
void set_cfgtimezonesid(::google::protobuf::uint32 value)
void set_cfgconfigsid(::google::protobuf::uint32 value)
void set_cfglanguagesid(::google::protobuf::uint32 value)
void set_family(::google::protobuf::uint32 value)
inline ::JSON::RealmList::IPAddress * add_addresses()
void set_gameaccount(const ::std::string &value)
void set_clientarch(::google::protobuf::uint32 value)
void set_type(::google::protobuf::uint32 value)
void set_platform(::google::protobuf::uint32 value)
inline ::JSON::RealmList::RealmIPAddressFamily * add_families()
void set_wowrealmaddress(::google::protobuf::uint32 value)
void set_deleting(bool value)
inline ::JSON::RealmList::RealmEntry * mutable_update()
inline ::JSON::RealmList::RealmListUpdatePart * add_updates()
void setBinary(uint8 index, std::vector< uint8 > &&value)
void setInt16(uint8 index, int16 value)
void setString(uint8 index, std::string &&value)
void setUInt32(uint8 index, uint32 value)
void setUInt8(uint8 index, uint8 value)
Storage object for the list of realms on the server.
void FillRealmEntry(Realm const &realm, uint32 clientBuild, AccountTypes accountSecurityLevel, JSON::RealmList::RealmEntry *realmEntry) const
std::shared_ptr< Realm const > GetCurrentRealm() const
std::map< Battlenet::RealmHandle, std::shared_ptr< Realm > > RealmMap
std::map< Battlenet::RealmHandle, std::string > _removedRealms
std::shared_ptr< Realm const > GetRealm(Battlenet::RealmHandle const &id) const
static void UpdateRealm(Realm &realm, Battlenet::RealmHandle const &id, uint32 build, std::string const &name, std::vector< boost::asio::ip::address > &&addresses, uint16 port, uint8 icon, RealmFlags flag, uint8 timezone, AccountTypes allowedSecurityLevel, RealmPopulationState population)
Battlenet::RealmHandle GetCurrentRealmId() const
std::vector< uint8 > GetRealmEntryJSON(Battlenet::RealmHandle const &id, uint32 build, AccountTypes accountSecurityLevel) const
void SetCurrentRealmId(Battlenet::RealmHandle const &id)
std::vector< uint8 > GetRealmList(uint32 build, AccountTypes accountSecurityLevel, std::string const &subRegion) const
std::unordered_set< std::string > _subRegions
Optional< Battlenet::RealmHandle > _currentRealmId
void Initialize(Trinity::Asio::IoContext &ioContext, uint32 updateInterval)
uint32 JoinRealm(uint32 realmAddress, uint32 build, ClientBuild::VariantId const &buildVariant, boost::asio::ip::address const &clientAddress, std::array< uint8, 32 > const &clientSecret, LocaleConstant locale, std::string const &os, Minutes timezoneOffset, std::string const &accountName, AccountTypes accountSecurityLevel, bgs::protocol::game_utilities::v1::ClientResponse *response) const
std::shared_mutex _realmsMutex
std::unique_ptr< Trinity::Net::Resolver > _resolver
std::unique_ptr< Trinity::Asio::DeadlineTimer > _updateTimer
static RealmList * Instance()
void WriteSubRegions(bgs::protocol::game_utilities::v1::GetAllValuesForAttributeResponse *response) const
inline ::bgs::protocol::Variant * mutable_value()
void set_name(const ::std::string &value)
void set_blob_value(const ::std::string &value)
void set_string_value(const ::std::string &value)
inline ::bgs::protocol::Attribute * add_attribute()
inline ::bgs::protocol::Variant * add_attribute_value()
Info const * GetBuildInfo(uint32 build)
TC_SHARED_API std::string Serialize(google::protobuf::Message const &message)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
struct advstd::ranges::Contains contains
std::string GetAddressString() const
uint32 GetAddress() const
AccountTypes AllowedSecurityLevel
uint32 GetConfigId() const
RealmPopulationState PopulationLevel
void SetName(std::string name)
Battlenet::RealmHandle Id
std::vector< boost::asio::ip::address > Addresses