private void SynchronizeOnlineServers()
{
IALFADatabase Database = DatabaseLinkQueryThread;
//
// Query the current server list and synchronize with our internal
// state.
//
// There are several steps here:
//
// 1) Mark all online servers as "not visited".
// 2) Retrieve the server list from the database. For each server
// that wasn't already marked as online, mark it as online.
// Also, flag any server that is in the list from the database
// as "visited".
// 3) Sweep the online server list for servers that are still
// flagged as "not visited". These servers are those that have
// gone offline in the interim time. Note that we don't yet
// update the player list, as that is handled by the player list
// synchronization tep.
//
//
// First - query the database. This query returns a list of all
// servers that have checked in during the past ten minutes. We
// treat any server that has not checked in within at least that
// long as being offline.
//
List<SynchronizeOnlineServersRow> Rowset = new List<SynchronizeOnlineServersRow>();
Database.ACR_SQLQuery(
"SELECT " +
"`servers`.`ID` AS server_id, " +
"`servers`.`IPAddress` as ip_address, " +
"`servers`.`IsPublic` as public_server " +
"FROM `servers` " +
"INNER JOIN `pwdata` ON `pwdata`.`Name` = `servers`.`Name` " +
"WHERE pwdata.`Key` = 'ACR_TIME_SERVERTIME' " +
"AND pwdata.`Last` >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 10 MINUTE) "
);
//
// Clear visited.
//
// N.B. The Visited flag is only managed on the query thread or
// prior to list insertion during initial server creation.
//
// Thus, while we must lock to protect the integrity of the
// list, there's no need to worry about another thread
// altering the Visited state after we drop the lock.
//
lock (this)
{
foreach (GameServer Server in Servers)
{
Server.Visited = false;
}
}
//
// Read each database row.
//
while (Database.ACR_SQLFetch())
{
SynchronizeOnlineServersRow Row;
Row.ServerId = Convert.ToInt32(Database.ACR_SQLGetData(0));
Row.AddressString = Database.ACR_SQLGetData(1);
Row.PublicServer = ConvertToBoolean(Database.ACR_SQLGetData(2));
Rowset.Add(Row);
}
lock (this)
{
//
// Update entries.
//
foreach (SynchronizeOnlineServersRow Row in Rowset)
{
int ServerId = Row.ServerId;
string AddressString = Row.AddressString;
GameServer Server = ReferenceServerById(ServerId, Database);
Server.Visited = true;
if (!Server.Online)
{
Server.Online = true;
Server.DatabaseOnline = true;
OnServerJoin(Server);
}
Server.SetHostnameAndPort(AddressString);
Server.Public = Row.PublicServer;
}
//
// Sweep offline servers.
//
var NowOfflineServers = (from S in Servers
where S.Visited == false &&
S.Online == true
select S);
List<GameServer> ObjectsToRemove = new List<GameServer>(NowOfflineServers);
foreach (GameServer Server in ObjectsToRemove)
{
Server.Online = false;
Server.DatabaseOnline = false;
OnServerPart(Server);
}
}
}