mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Save previously determined best serverlist
Also make the whole process more robust against failures, retry finding the best serverlist if the current one is broken.
This commit is contained in:
parent
9002c9f9a2
commit
53e9457965
|
@ -101,7 +101,6 @@ void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVers
|
|||
IConfigManager *pConfigManager = Kernel()->RequestInterface<IConfigManager>();
|
||||
if(pConfigManager)
|
||||
pConfigManager->RegisterCallback(ConfigSaveCallback, this);
|
||||
m_pHttp = CreateServerBrowserHttp(m_pEngine);
|
||||
m_pPingCache = CreateServerBrowserPingCache(m_pConsole, m_pStorage);
|
||||
|
||||
RegisterCommands();
|
||||
|
@ -1143,6 +1142,18 @@ void CServerBrowser::Update(bool ForceResort)
|
|||
int64 Timeout = time_freq();
|
||||
int64 Now = time_get();
|
||||
|
||||
if(!m_pHttp)
|
||||
{
|
||||
m_pHttp = CreateServerBrowserHttp(m_pEngine, m_pConsole, m_pStorage, g_Config.m_BrCachedBestServerinfoUrl);
|
||||
}
|
||||
|
||||
const char *pHttpBestUrl;
|
||||
if(!m_pHttp->GetBestUrl(&pHttpBestUrl) && pHttpBestUrl != m_pHttpPrevBestUrl)
|
||||
{
|
||||
str_copy(g_Config.m_BrCachedBestServerinfoUrl, pHttpBestUrl, sizeof(g_Config.m_BrCachedBestServerinfoUrl));
|
||||
m_pHttpPrevBestUrl = pHttpBestUrl;
|
||||
}
|
||||
|
||||
m_pHttp->Update();
|
||||
|
||||
if(m_ServerlistType != TYPE_LAN && m_RefreshingHttp && !m_pHttp->IsRefreshing())
|
||||
|
|
|
@ -153,6 +153,7 @@ private:
|
|||
bool m_RefreshingHttp = false;
|
||||
IServerBrowserHttp *m_pHttp = nullptr;
|
||||
IServerBrowserPingCache *m_pPingCache = nullptr;
|
||||
const char *m_pHttpPrevBestUrl = nullptr;
|
||||
|
||||
CHeap m_ServerlistHeap;
|
||||
CServerEntry **m_ppServerlist;
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
|
||||
#include "http.h"
|
||||
|
||||
#include <engine/console.h>
|
||||
#include <engine/engine.h>
|
||||
#include <engine/external/json-parser/json.h>
|
||||
#include <engine/serverbrowser.h>
|
||||
#include <engine/shared/linereader.h>
|
||||
#include <engine/shared/serverinfo.h>
|
||||
#include <engine/storage.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -21,11 +24,14 @@ public:
|
|||
CChooseMaster(IEngine *pEngine, VALIDATOR pfnValidator, const char **ppUrls, int NumUrls, int PreviousBestIndex);
|
||||
virtual ~CChooseMaster() {}
|
||||
|
||||
const char *GetBestUrl() const;
|
||||
int GetBestIndex() const;
|
||||
bool GetBestUrl(const char **pBestUrl) const;
|
||||
void Reset();
|
||||
bool IsRefreshing() const { return m_pJob && m_pJob->Status() != IJob::STATE_DONE; }
|
||||
void Refresh();
|
||||
|
||||
private:
|
||||
int GetBestIndex() const;
|
||||
|
||||
class CData
|
||||
{
|
||||
public:
|
||||
|
@ -49,6 +55,7 @@ private:
|
|||
IEngine *m_pEngine;
|
||||
int m_PreviousBestIndex;
|
||||
std::shared_ptr<CData> m_pData;
|
||||
std::shared_ptr<CJob> m_pJob;
|
||||
};
|
||||
|
||||
CChooseMaster::CChooseMaster(IEngine *pEngine, VALIDATOR pfnValidator, const char **ppUrls, int NumUrls, int PreviousBestIndex) :
|
||||
|
@ -66,10 +73,6 @@ CChooseMaster::CChooseMaster(IEngine *pEngine, VALIDATOR pfnValidator, const cha
|
|||
{
|
||||
str_copy(m_pData->m_aaUrls[i], ppUrls[i], sizeof(m_pData->m_aaUrls[i]));
|
||||
}
|
||||
if(m_PreviousBestIndex < 0)
|
||||
{
|
||||
m_PreviousBestIndex = secure_rand_below(NumUrls);
|
||||
}
|
||||
}
|
||||
|
||||
int CChooseMaster::GetBestIndex() const
|
||||
|
@ -85,14 +88,27 @@ int CChooseMaster::GetBestIndex() const
|
|||
}
|
||||
}
|
||||
|
||||
const char *CChooseMaster::GetBestUrl() const
|
||||
bool CChooseMaster::GetBestUrl(const char **ppBestUrl) const
|
||||
{
|
||||
return m_pData->m_aaUrls[GetBestIndex()];
|
||||
int Index = GetBestIndex();
|
||||
if(Index < 0)
|
||||
{
|
||||
*ppBestUrl = nullptr;
|
||||
return true;
|
||||
}
|
||||
*ppBestUrl = m_pData->m_aaUrls[Index];
|
||||
return false;
|
||||
}
|
||||
|
||||
void CChooseMaster::Reset()
|
||||
{
|
||||
m_PreviousBestIndex = -1;
|
||||
m_pData->m_BestIndex.store(-1);
|
||||
}
|
||||
|
||||
void CChooseMaster::Refresh()
|
||||
{
|
||||
m_pEngine->AddJob(std::make_shared<CJob>(m_pData));
|
||||
m_pEngine->AddJob(m_pJob = std::make_shared<CJob>(m_pData));
|
||||
}
|
||||
|
||||
void CChooseMaster::CJob::Run()
|
||||
|
@ -176,11 +192,12 @@ void CChooseMaster::CJob::Run()
|
|||
class CServerBrowserHttp : public IServerBrowserHttp
|
||||
{
|
||||
public:
|
||||
CServerBrowserHttp(IEngine *pEngine);
|
||||
CServerBrowserHttp(IEngine *pEngine, IConsole *pConsole, const char **ppUrls, int NumUrls, int PreviousBestIndex);
|
||||
virtual ~CServerBrowserHttp() {}
|
||||
void Update();
|
||||
bool IsRefreshing() { return (bool)m_pGetServers; }
|
||||
bool IsRefreshing() { return m_State != STATE_DONE; }
|
||||
void Refresh();
|
||||
bool GetBestUrl(const char **pBestUrl) const { return m_pChooseMaster->GetBestUrl(pBestUrl); }
|
||||
|
||||
int NumServers() const
|
||||
{
|
||||
|
@ -206,6 +223,13 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
STATE_DONE,
|
||||
STATE_WANTREFRESH,
|
||||
STATE_REFRESHING,
|
||||
};
|
||||
|
||||
class CEntry
|
||||
{
|
||||
public:
|
||||
|
@ -217,6 +241,9 @@ private:
|
|||
static bool Parse(json_value *pJson, std::vector<CEntry> *paServers, std::vector<NETADDR> *paLegacyServers);
|
||||
|
||||
IEngine *m_pEngine;
|
||||
IConsole *m_pConsole;
|
||||
|
||||
int m_State = STATE_DONE;
|
||||
std::shared_ptr<CGet> m_pGetServers;
|
||||
std::unique_ptr<CChooseMaster> m_pChooseMaster;
|
||||
|
||||
|
@ -224,40 +251,61 @@ private:
|
|||
std::vector<NETADDR> m_aLegacyServers;
|
||||
};
|
||||
|
||||
static const char *MASTERSERVER_URLS[] = {
|
||||
"https://heinrich5991.de/teeworlds/temp/xyz.json",
|
||||
"https://heinrich5991.de/teeworlds/temp/servers.json",
|
||||
};
|
||||
|
||||
CServerBrowserHttp::CServerBrowserHttp(IEngine *pEngine) :
|
||||
CServerBrowserHttp::CServerBrowserHttp(IEngine *pEngine, IConsole *pConsole, const char **ppUrls, int NumUrls, int PreviousBestIndex) :
|
||||
m_pEngine(pEngine),
|
||||
m_pChooseMaster(new CChooseMaster(pEngine, Validate, MASTERSERVER_URLS, sizeof(MASTERSERVER_URLS) / sizeof(MASTERSERVER_URLS[0]), -1))
|
||||
m_pConsole(pConsole),
|
||||
m_pChooseMaster(new CChooseMaster(pEngine, Validate, ppUrls, NumUrls, PreviousBestIndex))
|
||||
{
|
||||
m_pChooseMaster->Refresh();
|
||||
}
|
||||
void CServerBrowserHttp::Update()
|
||||
{
|
||||
if(m_pGetServers && m_pGetServers->State() != HTTP_QUEUED && m_pGetServers->State() != HTTP_RUNNING)
|
||||
if(m_State == STATE_WANTREFRESH)
|
||||
{
|
||||
std::shared_ptr<CGet> pGetServers = nullptr;
|
||||
std::swap(m_pGetServers, pGetServers);
|
||||
|
||||
json_value *pJson = pGetServers->ResultJson();
|
||||
if(!pJson)
|
||||
const char *pBestUrl;
|
||||
if(m_pChooseMaster->GetBestUrl(&pBestUrl))
|
||||
{
|
||||
if(!m_pChooseMaster->IsRefreshing())
|
||||
{
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "serverbrowse_http", "no working serverlist URL found");
|
||||
m_State = STATE_DONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
m_pEngine->AddJob(m_pGetServers = std::make_shared<CGet>(pBestUrl, CTimeout{0, 0, 0}));
|
||||
m_State = STATE_REFRESHING;
|
||||
}
|
||||
else if(m_State == STATE_REFRESHING)
|
||||
{
|
||||
if(m_pGetServers->State() == HTTP_QUEUED || m_pGetServers->State() == HTTP_RUNNING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool ParseFailure = Parse(pJson, &m_aServers, &m_aLegacyServers);
|
||||
m_State = STATE_DONE;
|
||||
std::shared_ptr<CGet> pGetServers = nullptr;
|
||||
std::swap(m_pGetServers, pGetServers);
|
||||
|
||||
bool Success = true;
|
||||
json_value *pJson = pGetServers->ResultJson();
|
||||
Success = Success && pJson;
|
||||
Success = Success && !Parse(pJson, &m_aServers, &m_aLegacyServers);
|
||||
json_value_free(pJson);
|
||||
if(ParseFailure)
|
||||
if(!Success)
|
||||
{
|
||||
return;
|
||||
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "serverbrowse_http", "failed getting serverlist, trying to find best URL");
|
||||
m_pChooseMaster->Reset();
|
||||
m_pChooseMaster->Refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
void CServerBrowserHttp::Refresh()
|
||||
{
|
||||
m_pEngine->AddJob(m_pGetServers = std::make_shared<CGet>(m_pChooseMaster->GetBestUrl(), CTimeout{0, 0, 0}));
|
||||
if(m_State == STATE_WANTREFRESH)
|
||||
{
|
||||
m_pChooseMaster->Refresh();
|
||||
}
|
||||
m_State = STATE_WANTREFRESH;
|
||||
Update();
|
||||
}
|
||||
bool ServerbrowserParseUrl(NETADDR *pOut, const char *pUrl)
|
||||
{
|
||||
|
@ -333,7 +381,7 @@ bool CServerBrowserHttp::Parse(json_value *pJson, std::vector<CEntry> *paServers
|
|||
}
|
||||
if(CServerInfo2::FromJson(&ParsedInfo, &Info))
|
||||
{
|
||||
dbg_msg("dbg/serverbrowser", "skipped due to info, i=%d", i);
|
||||
//dbg_msg("dbg/serverbrowser", "skipped due to info, i=%d", i);
|
||||
// Only skip the current server on parsing
|
||||
// failure; the server info is "user input" by
|
||||
// the game server and can be set to arbitrary
|
||||
|
@ -353,7 +401,7 @@ bool CServerBrowserHttp::Parse(json_value *pJson, std::vector<CEntry> *paServers
|
|||
NETADDR ParsedAddr;
|
||||
if(ServerbrowserParseUrl(&ParsedAddr, Addresses[a]))
|
||||
{
|
||||
dbg_msg("dbg/serverbrowser", "unknown address, i=%d a=%d", i, a);
|
||||
//dbg_msg("dbg/serverbrowser", "unknown address, i=%d a=%d", i, a);
|
||||
// Skip unknown addresses.
|
||||
continue;
|
||||
}
|
||||
|
@ -377,7 +425,50 @@ bool CServerBrowserHttp::Parse(json_value *pJson, std::vector<CEntry> *paServers
|
|||
*paLegacyServers = aLegacyServers;
|
||||
return false;
|
||||
}
|
||||
IServerBrowserHttp *CreateServerBrowserHttp(IEngine *pEngine)
|
||||
|
||||
static const char *DEFAULT_SERVERLIST_URLS[] = {
|
||||
"https://master1.ddnet.tw/ddnet/15/servers.json",
|
||||
"https://master2.ddnet.tw/ddnet/15/servers.json",
|
||||
"https://master3.ddnet.tw/ddnet/15/servers.json",
|
||||
"https://master4.ddnet.tw/ddnet/15/servers.json",
|
||||
};
|
||||
|
||||
IServerBrowserHttp *CreateServerBrowserHttp(IEngine *pEngine, IConsole *pConsole, IStorage *pStorage, const char *pPreviousBestUrl)
|
||||
{
|
||||
return new CServerBrowserHttp(pEngine);
|
||||
char aaUrls[CChooseMaster::MAX_URLS][256];
|
||||
const char *apUrls[CChooseMaster::MAX_URLS];
|
||||
const char **ppUrls = apUrls;
|
||||
int NumUrls = 0;
|
||||
IOHANDLE File = pStorage->OpenFile("serverlist_urls.cfg", IOFLAG_READ, IStorage::TYPE_ALL);
|
||||
if(File)
|
||||
{
|
||||
CLineReader Lines;
|
||||
Lines.Init(File);
|
||||
while(NumUrls < CChooseMaster::MAX_URLS)
|
||||
{
|
||||
const char *pLine = Lines.Get();
|
||||
if(!pLine)
|
||||
{
|
||||
break;
|
||||
}
|
||||
str_copy(aaUrls[NumUrls], pLine, sizeof(aaUrls[NumUrls]));
|
||||
apUrls[NumUrls] = aaUrls[NumUrls];
|
||||
NumUrls += 1;
|
||||
}
|
||||
}
|
||||
if(NumUrls == 0)
|
||||
{
|
||||
ppUrls = DEFAULT_SERVERLIST_URLS;
|
||||
NumUrls = sizeof(DEFAULT_SERVERLIST_URLS) / sizeof(DEFAULT_SERVERLIST_URLS[0]);
|
||||
}
|
||||
int PreviousBestIndex = -1;
|
||||
for(int i = 0; i < NumUrls; i++)
|
||||
{
|
||||
if(str_comp(ppUrls[i], pPreviousBestUrl) == 0)
|
||||
{
|
||||
PreviousBestIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new CServerBrowserHttp(pEngine, pConsole, ppUrls, NumUrls, PreviousBestIndex);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
#include <base/system.h>
|
||||
|
||||
class CServerInfo;
|
||||
class IConsole;
|
||||
class IEngine;
|
||||
class IStorage;
|
||||
|
||||
class IServerBrowserHttp
|
||||
{
|
||||
|
@ -15,6 +17,8 @@ public:
|
|||
virtual bool IsRefreshing() = 0;
|
||||
virtual void Refresh() = 0;
|
||||
|
||||
virtual bool GetBestUrl(const char **pBestUrl) const = 0;
|
||||
|
||||
virtual int NumServers() const = 0;
|
||||
virtual const NETADDR &ServerAddress(int Index) const = 0;
|
||||
virtual void Server(int Index, NETADDR *pAddr, CServerInfo *pInfo) const = 0;
|
||||
|
@ -22,5 +26,5 @@ public:
|
|||
virtual const NETADDR &LegacyServer(int Index) const = 0;
|
||||
};
|
||||
|
||||
IServerBrowserHttp *CreateServerBrowserHttp(IEngine *pEngine);
|
||||
IServerBrowserHttp *CreateServerBrowserHttp(IEngine *pEngine, IConsole *pConsole, IStorage *pStorage, const char *pPreviousBestUrl);
|
||||
#endif // ENGINE_CLIENT_SERVERBROWSER_HTTP_H
|
||||
|
|
|
@ -64,6 +64,7 @@ MACRO_CONFIG_STR(BrFilterExcludeCountries, br_filter_exclude_countries, 128, "",
|
|||
MACRO_CONFIG_STR(BrFilterExcludeTypes, br_filter_exclude_types, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out DDNet servers by type (mod)")
|
||||
MACRO_CONFIG_INT(BrIndicateFinished, br_indicate_finished, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show whether you have finished a DDNet map (transmits your player name to info2.ddnet.tw/info)")
|
||||
MACRO_CONFIG_STR(BrLocation, br_location, 16, "auto", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Override location for ping estimation, available: auto, af, as, as:cn, eu, na, oc, sa (Automatic, Africa, Asia, China, Europe, North America, Oceania/Australia, South America")
|
||||
MACRO_CONFIG_STR(BrCachedBestServerinfoUrl, br_cached_best_serverinfo_url, 256, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Do not set this variable, instead create a serverlist_urls.cfg next to settings_ddnet.cfg to specify all possible serverlist URLs")
|
||||
|
||||
MACRO_CONFIG_STR(BrFilterExcludeCountriesKoG, br_filter_exclude_countries_kog, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out kog servers by country")
|
||||
MACRO_CONFIG_STR(BrFilterExcludeTypesKoG, br_filter_exclude_types_kog, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out kog servers by type (mod)")
|
||||
|
|
Loading…
Reference in a new issue