Implement node serverlist for the client.

This commit is contained in:
momo5502 2016-02-03 20:10:54 +01:00
parent a9ecaf139f
commit 7bd8feff5d
3 changed files with 158 additions and 93 deletions

View File

@ -214,6 +214,21 @@ namespace Components
} }
} }
std::vector<Network::Address> Node::GetDediList()
{
std::vector<Network::Address> dedis;
for (auto dedi : Node::Dedis)
{
if (dedi.state == Node::STATE_VALID)
{
dedis.push_back(dedi.address);
}
}
return dedis;
}
void Node::DeleteInvalidNodes() void Node::DeleteInvalidNodes()
{ {
std::vector<Node::NodeEntry> cleanNodes; std::vector<Node::NodeEntry> cleanNodes;
@ -237,6 +252,92 @@ namespace Components
} }
} }
void Node::FrameHandler()
{
int heartbeatCount = 0;
int count = 0;
// Send requests
for (auto &node : Node::Nodes)
{
if (count < NODE_FRAME_QUERY_LIMIT && (node.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */node.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) >(NODE_VALIDITY_EXPIRE))))
{
count++;
node.lastTime = Game::Com_Milliseconds();
node.state = Node::STATE_QUERYING;
Logger::Print("Syncing with node %s...\n", node.address.GetString());
// Request new lists
Network::Send(node.address, "nodeRequestLists");
// Send our lists (only if dedi)
if (Dedicated::IsDedicated())
{
Node::SendNodeList(node.address);
Node::SendDediList(node.address);
}
}
if (node.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) > (NODE_QUERY_TIMEOUT))
{
node.state = Node::STATE_INVALID;
node.lastTime = Game::Com_Milliseconds();
}
if (Dedicated::IsDedicated() && node.state == Node::STATE_VALID)
{
if (heartbeatCount < HEARTBEATS_FRAME_LIMIT && (!node.lastHeartbeat || (Game::Com_Milliseconds() - node.lastHeartbeat) >(HEARTBEAT_INTERVAL)))
{
heartbeatCount++;
Logger::Print("Sending heartbeat to node %s...\n", node.address.GetString());
node.lastHeartbeat = Game::Com_Milliseconds();
Network::Send(node.address, "heartbeat\n");
}
}
}
count = 0;
for (auto &dedi : Node::Dedis)
{
if (count < DEDI_FRAME_QUERY_LIMIT && (dedi.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */dedi.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) >(DEDI_VALIDITY_EXPIRE))))
{
count++;
dedi.lastTime = Game::Com_Milliseconds();
dedi.challenge = Utils::VA("%d", dedi.lastTime);
dedi.state = Node::STATE_QUERYING;
Logger::Print("Verifying dedi %s...\n", dedi.address.GetString());
// Request new lists
Network::Send(dedi.address, Utils::VA("getinfo %s\n", dedi.challenge.data()));
}
// No query response
if (dedi.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) > (DEDI_QUERY_TIMEOUT))
{
dedi.state = Node::STATE_INVALID;
dedi.lastTime = Game::Com_Milliseconds();
}
// Lack of heartbeats
if (dedi.state == Node::STATE_VALID && (Game::Com_Milliseconds() - dedi.lastTime) > (HEARTBEAT_DEADLINE))
{
Logger::Print("Invalidating dedi %s\n", dedi.address.GetString());
dedi.state = Node::STATE_INVALID;
}
}
Node::DeleteInvalidNodes();
Node::DeleteInvalidDedis();
count = 0;
}
void Node::DeleteInvalidDedis() void Node::DeleteInvalidDedis()
{ {
std::vector<Node::DediEntry> cleanDedis; std::vector<Node::DediEntry> cleanDedis;
@ -260,10 +361,33 @@ namespace Components
} }
} }
const char* Node::GetStateName(EntryState state)
{
switch (state)
{
case Node::STATE_UNKNOWN:
return "Unknown";
case Node::STATE_QUERYING:
return "Querying";
case Node::STATE_INVALID:
return "Invalid";
case Node::STATE_VALID:
return "Valid";
}
return "";
}
Node::Node() Node::Node()
{ {
Assert_Size(Node::AddressEntry, 6); Assert_Size(Node::AddressEntry, 6);
// ZoneBuilder doesn't require node stuff
if (ZoneBuilder::IsEnabled()) return;
Dvar::OnInit([] () Dvar::OnInit([] ()
{ {
Node::Dedis.clear(); Node::Dedis.clear();
@ -282,16 +406,17 @@ namespace Components
}); });
} }
Network::Handle("nodeRequestLists", [] (Network::Address address, std::string data) // Only dedis act as nodes!
if (Dedicated::IsDedicated())
{ {
Logger::Print("Sending our lists to %s\n", address.GetString()); Network::Handle("nodeRequestLists", [] (Network::Address address, std::string data)
{
Logger::Print("Sending our lists to %s\n", address.GetString());
// Consider this a node for now! Node::SendNodeList(address);
//Node::AddNode(address, true); Node::SendDediList(address);
});
Node::SendNodeList(address); }
Node::SendDediList(address);
});
Network::Handle("nodeNodeList", [] (Network::Address address, std::string data) Network::Handle("nodeNodeList", [] (Network::Address address, std::string data)
{ {
@ -366,96 +491,13 @@ namespace Components
} }
}); });
Dedicated::OnFrame([] ()
{
int heartbeatCount = 0;
int count = 0;
// Send requests
for (auto &node : Node::Nodes)
{
if (count < NODE_FRAME_QUERY_LIMIT && (node.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */node.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) >(NODE_VALIDITY_EXPIRE))))
{
count++;
node.lastTime = Game::Com_Milliseconds();
node.state = Node::STATE_QUERYING;
Logger::Print("Syncing with node %s...\n", node.address.GetString());
// Request new lists
Network::Send(node.address, "nodeRequestLists");
// Send our lists
Node::SendNodeList(node.address);
Node::SendDediList(node.address);
}
if (node.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - node.lastTime) > (NODE_QUERY_TIMEOUT))
{
node.state = Node::STATE_INVALID;
node.lastTime = Game::Com_Milliseconds();
}
if (node.state == Node::STATE_VALID)
{
if (heartbeatCount < HEARTBEATS_FRAME_LIMIT && (!node.lastHeartbeat || (Game::Com_Milliseconds() - node.lastHeartbeat) >(HEARTBEAT_INTERVAL)))
{
heartbeatCount++;
Logger::Print("Sending heartbeat to node %s...\n", node.address.GetString());
node.lastHeartbeat = Game::Com_Milliseconds();
Network::Send(node.address, "heartbeat\n");
}
}
}
count = 0;
for (auto &dedi : Node::Dedis)
{
if (count < DEDI_FRAME_QUERY_LIMIT && (dedi.state == Node::STATE_UNKNOWN || (/*node.state != Node::STATE_INVALID && */dedi.state != Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) >(DEDI_VALIDITY_EXPIRE))))
{
count++;
dedi.lastTime = Game::Com_Milliseconds();
dedi.challenge = Utils::VA("%d", dedi.lastTime);
dedi.state = Node::STATE_QUERYING;
Logger::Print("Verifying dedi %s...\n", dedi.address.GetString());
// Request new lists
Network::Send(dedi.address, Utils::VA("getinfo %s\n", dedi.challenge.data()));
}
// No query response
if (dedi.state == Node::STATE_QUERYING && (Game::Com_Milliseconds() - dedi.lastTime) > (DEDI_QUERY_TIMEOUT))
{
dedi.state = Node::STATE_INVALID;
dedi.lastTime = Game::Com_Milliseconds();
}
// Lack of heartbeats
if (dedi.state == Node::STATE_VALID && (Game::Com_Milliseconds() - dedi.lastTime) > (HEARTBEAT_DEADLINE))
{
Logger::Print("Invalidating dedi %s\n", dedi.address.GetString());
dedi.state = Node::STATE_INVALID;
}
}
Node::DeleteInvalidNodes();
Node::DeleteInvalidDedis();
count = 0;
});
Command::Add("listnodes", [] (Command::Params params) Command::Add("listnodes", [] (Command::Params params)
{ {
Logger::Print("Nodes: %d\n", Node::Nodes.size()); Logger::Print("Nodes: %d\n", Node::Nodes.size());
for (auto node : Node::Nodes) for (auto node : Node::Nodes)
{ {
Logger::Print("%s\n", node.address.GetString()); Logger::Print("%s\t(%s)\n", node.address.GetString(), Node::GetStateName(node.state));
} }
}); });
@ -465,7 +507,7 @@ namespace Components
for (auto dedi : Node::Dedis) for (auto dedi : Node::Dedis)
{ {
Logger::Print("%s\n", dedi.address.GetString()); Logger::Print("%s\t(%s)\n", dedi.address.GetString(), Node::GetStateName(dedi.state));
} }
}); });
@ -508,6 +550,10 @@ namespace Components
} }
} }
}); });
// Install frame handlers
Dedicated::OnFrame(Node::FrameHandler);
Renderer::OnFrame(Node::FrameHandler);
} }
Node::~Node() Node::~Node()

View File

@ -28,6 +28,8 @@ namespace Components
static void ValidateDedi(Network::Address address, Utils::InfoString info); static void ValidateDedi(Network::Address address, Utils::InfoString info);
static std::vector<Network::Address> GetDediList();
private: private:
enum EntryState enum EntryState
{ {
@ -94,5 +96,9 @@ namespace Components
static void DeleteInvalidNodes(); static void DeleteInvalidNodes();
static void DeleteInvalidDedis(); static void DeleteInvalidDedis();
static void FrameHandler();
static const char* GetStateName(EntryState state);
}; };
} }

View File

@ -213,6 +213,7 @@ namespace Components
} }
else if (ServerList::IsOnlineList()) else if (ServerList::IsOnlineList())
{ {
#ifdef USE_LEGACY_SERVER_LIST
ServerList::RefreshContainer.AwatingList = true; ServerList::RefreshContainer.AwatingList = true;
ServerList::RefreshContainer.AwaitTime = Game::Com_Milliseconds(); ServerList::RefreshContainer.AwaitTime = Game::Com_Milliseconds();
@ -225,6 +226,18 @@ namespace Components
Network::Send(ServerList::RefreshContainer.Host, Utils::VA("getservers IW4 %i full empty", PROTOCOL)); Network::Send(ServerList::RefreshContainer.Host, Utils::VA("getservers IW4 %i full empty", PROTOCOL));
//Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n"); //Network::Send(ServerList::RefreshContainer.Host, "getservers 0 full empty\n");
#else
ServerList::RefreshContainer.Mutex.lock();
auto dedis = Node::GetDediList();
for (auto dedi : dedis)
{
ServerList::InsertRequest(dedi, false);
}
ServerList::RefreshContainer.Mutex.unlock();
#endif
} }
else if (ServerList::IsFavouriteList()) else if (ServerList::IsFavouriteList())
{ {