28#include "RealmList.pb.h"
30#include <boost/asio/ip/tcp.hpp>
35bool CompressJson(std::string
const& json, std::vector<uint8>* compressed)
37 uLong uncompressedLength = uLong(json.length() + 1);
38 uLong compressedLength = compressBound(uLong(json.length()));
39 compressed->resize(compressedLength + 4);
40 memcpy(compressed->data(), &uncompressedLength,
sizeof(uncompressedLength));
42 if (compress(compressed->data() + 4, &compressedLength,
reinterpret_cast<uint8 const*
>(json.data()), uncompressedLength) != Z_OK)
48 compressed->resize(compressedLength + 4);
69 _updateTimer = std::make_unique<Trinity::Asio::DeadlineTimer>(ioContext);
70 _resolver = std::make_unique<Trinity::Net::Resolver>(ioContext);
83 std::vector<boost::asio::ip::address>&& addresses,
89 if (realm.
Name != name)
107 std::map<Battlenet::RealmHandle, std::string> existingRealms;
109 existingRealms[p.first] = p.second->Name;
111 std::unordered_set<std::string> newSubRegions;
119 Field* fields = result->Fetch();
121 std::string name = fields[1].
GetString();
122 std::vector<boost::asio::ip::address> addresses;
124 for (std::size_t i = 0; i < 4; ++i)
128 for (boost::asio::ip::tcp::endpoint
const& endpoint :
_resolver->ResolveAll(*addressStr,
""))
130 boost::asio::ip::address address = endpoint.address();
134 addresses.push_back(std::move(address));
139 if (addresses.empty())
141 TC_LOG_ERROR(
"realmlist",
"Could not resolve any address for realm \"{}\" id {}", name, realmId);
161 UpdateRealm(*newRealms.try_emplace(
id, std::make_shared<Realm>()).first->second,
id, build, name, std::move(addresses), port, icon,
166 auto buildAddressesLogText = [&]
169 for (boost::asio::ip::address
const& address : newRealms[id]->Addresses)
171 text += address.to_string();
177 if (!existingRealms.erase(
id))
178 TC_LOG_INFO(
"realmlist",
"Added realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port);
180 TC_LOG_DEBUG(
"realmlist",
"Updating realm \"{}\" at {}(port {}).", name, buildAddressesLogText(), port);
182 while (result->NextRow());
185 for (
auto itr = existingRealms.begin(); itr != existingRealms.end(); ++itr)
186 TC_LOG_INFO(
"realmlist",
"Removed realm \"{}\".", itr->second);
203 _updateTimer->async_wait([
this](boost::system::error_code
const& error)
245 realmEntry->set_cfgtimezonesid(1);
251 realmEntry->set_cfgcategoriesid(realm.
Timezone);
253 JSON::RealmList::ClientVersion* version = realmEntry->mutable_version();
256 version->set_versionmajor(buildInfo->MajorVersion);
257 version->set_versionminor(buildInfo->MinorVersion);
258 version->set_versionrevision(buildInfo->BugfixVersion);
259 version->set_versionbuild(buildInfo->Build);
263 version->set_versionmajor(6);
264 version->set_versionminor(2);
265 version->set_versionrevision(4);
266 version->set_versionbuild(realm.
Build);
270 if (realm.
Build != clientBuild)
273 realmEntry->set_cfgrealmsid(realm.
Id.
Realm);
275 realmEntry->set_name(realm.
Name);
277 realmEntry->set_cfglanguagesid(1);
278 realmEntry->set_cfgcontentsetid(0);
279 realmEntry->set_usebleepchance(0.0f);
284 if (std::shared_ptr<Realm const> realm =
GetRealm(
id))
288 JSON::RealmList::RealmEntry realmEntry;
299 JSON::RealmList::RealmListUpdates realmList;
302 for (
auto const& [_, realm] :
_realms)
304 if (realm->Id.GetSubRegionAddress() != subRegion)
307 JSON::RealmList::RealmListUpdatePart* state = realmList.add_updates();
308 FillRealmEntry(*realm, build, accountSecurityLevel, state->mutable_update());
309 state->set_deleting(
false);
314 if (
id.GetSubRegionAddress() != subRegion)
317 JSON::RealmList::RealmListUpdatePart* state = realmList.add_updates();
318 state->set_wowrealmaddress(
id.GetAddress());
319 state->set_deleting(
true);
323 std::string json =
"JSONRealmListUpdates:" +
JSON::Serialize(realmList);
324 std::vector<uint8> compressed;
325 CompressJson(json, &compressed);
330 std::array<uint8, 32>
const& clientSecret,
LocaleConstant locale, std::string
const& os,
Minutes timezoneOffset, std::string
const& accountName,
333 if (std::shared_ptr<Realm const> realm =
GetRealm(realmAddress))
338 boost::asio::ip::address addressForClient = realm->GetAddressForClient(clientAddress);
340 JSON::RealmList::RealmListServerIPAddresses serverAddresses;
341 JSON::RealmList::RealmIPAddressFamily* addressFamily = serverAddresses.add_families();
342 addressFamily->set_family(addressForClient.is_v6() ? 2 : 1);
344 JSON::RealmList::IPAddress* address = addressFamily->add_addresses();
345 address->set_ip(addressForClient.to_string());
346 address->set_port(realm->Port);
348 std::string json =
"JSONRealmListServerIPAddresses:" +
JSON::Serialize(serverAddresses);
349 std::vector<uint8> serverAddressesCompressed;
351 if (!CompressJson(json, &serverAddressesCompressed))
354 std::vector<uint8> serverSecret(32);
357 std::array<uint8, 64> keyData;
358 auto keyDestItr = keyData.begin();
359 keyDestItr = std::ranges::copy(clientSecret, keyDestItr).out;
360 keyDestItr = std::ranges::copy(serverSecret, keyDestItr).out;
364 stmt->
setString(1, clientAddress.to_string());
368 stmt->
setInt16(5, timezoneOffset.count());
372 JSON::RealmList::RealmJoinTicket joinTicket;
373 joinTicket.set_gameaccount(accountName);
374 joinTicket.set_platform(buildVariant.
Platform);
375 joinTicket.set_clientarch(buildVariant.
Arch);
376 joinTicket.set_type(buildVariant.
Type);
382 .JoinTicket = { joinTicketJson.begin(), joinTicketJson.end() },
383 .ServerAddresses = std::move(serverAddressesCompressed),
384 .JoinSecret = std::move(serverSecret)
@ 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 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
void SetCurrentRealmId(Battlenet::RealmHandle const &id)
std::vector< uint8 > GetRealmList(uint32 build, AccountTypes accountSecurityLevel, std::string const &subRegion) const
std::string GetRealmEntryJSON(Battlenet::RealmHandle const &id, uint32 build, AccountTypes accountSecurityLevel) const
std::unordered_set< std::string > _subRegions
Optional< Battlenet::RealmHandle > _currentRealmId
void Initialize(Trinity::Asio::IoContext &ioContext, uint32 updateInterval)
std::shared_mutex _realmsMutex
std::vector< std::string > GetSubRegions() const
std::unique_ptr< Trinity::Net::Resolver > _resolver
std::unique_ptr< Trinity::Asio::DeadlineTimer > _updateTimer
static RealmList * Instance()
RealmJoinResult 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) const
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)
std::array< uint8, S > GetRandomBytes()
struct advstd::ranges::Contains contains
std::string GetAddressString() const
uint32 GetAddress() const
ClientBuild::Type::Id Type
ClientBuild::Arch::Id Arch
ClientBuild::Platform::Id Platform
AccountTypes AllowedSecurityLevel
uint32 GetConfigId() const
RealmPopulationState PopulationLevel
void SetName(std::string name)
Battlenet::RealmHandle Id
std::vector< boost::asio::ip::address > Addresses