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()
{
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()
{
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()
{
Assert_Size(Node::AddressEntry, 6);
// ZoneBuilder doesn't require node stuff
if (ZoneBuilder::IsEnabled()) return;
Dvar::OnInit([] ()
{
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::AddNode(address, true);
Node::SendNodeList(address);
Node::SendDediList(address);
});
Node::SendNodeList(address);
Node::SendDediList(address);
});
}
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)
{
Logger::Print("Nodes: %d\n", Node::Nodes.size());
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)
{
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()

View File

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

View File

@ -213,6 +213,7 @@ namespace Components
}
else if (ServerList::IsOnlineList())
{
#ifdef USE_LEGACY_SERVER_LIST
ServerList::RefreshContainer.AwatingList = true;
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, "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())
{