made the graphs load faster

fixed issues with stats page
made the pages json request faster
This commit is contained in:
RaidMax 2017-10-04 18:01:04 -05:00
parent 9758e72f6b
commit d8b19f289a
11 changed files with 137 additions and 129 deletions

View File

@ -54,6 +54,7 @@ namespace IW4MAdmin
if (requestedPage.content != null && requestedPage.content.GetType() != typeof(string))
requestedPage.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedPage.content);
string maxAge = requestedPage.contentType == "application/json" ? "0" : "31536000";
var headers = new HttpResponseHead()
{
Status = "200 OK",
@ -62,6 +63,7 @@ namespace IW4MAdmin
{ "Content-Type", requestedPage.contentType },
{ "Content-Length", binaryContent ? requestedPage.BinaryContent.Length.ToString() : requestedPage.content.ToString().Length.ToString() },
{ "Access-Control-Allow-Origin", "*" },
{ "Cache-Control", $"public,max-age={maxAge}"}
}
};

View File

@ -15,7 +15,8 @@ namespace IW4MAdmin
{
class ApplicationManager : IManager
{
public List<Server> Servers { get; private set; }
private List<Server> _servers;
public List<Server> Servers => _servers.OrderByDescending(s => s.ClientNum).ToList();
public ILogger Logger { get; private set; }
public bool Running { get; private set; }
@ -38,7 +39,7 @@ namespace IW4MAdmin
private ApplicationManager()
{
Logger = new Logger("Logs/IW4MAdmin.log");
Servers = new List<Server>();
_servers = new List<Server>();
Commands = new List<Command>();
TaskStatuses = new List<AsyncStatus>();
MessageTokens = new List<MessageToken>();
@ -113,9 +114,9 @@ namespace IW4MAdmin
var ServerInstance = new IW4MServer(this, Conf);
await ServerInstance.Initialize();
lock (Servers)
lock (_servers)
{
Servers.Add(ServerInstance);
_servers.Add(ServerInstance);
}
Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}");
@ -210,7 +211,7 @@ namespace IW4MAdmin
foreach (var S in Servers)
S.Broadcast("^1IW4MAdmin going offline!");
#endif
Servers.Clear();
_servers.Clear();
WebThread.Abort();
webServiceTask.Stop();
}
@ -250,7 +251,7 @@ namespace IW4MAdmin
{
var ActiveClients = new List<Player>();
foreach (var server in Servers)
foreach (var server in _servers)
ActiveClients.AddRange(server.Players.Where(p => p != null));
return ActiveClients;

View File

@ -206,8 +206,6 @@ namespace IW4MAdmin
public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
var info = new List<ServerInfo>();
int i = 0;
foreach (Server S in ApplicationManager.GetInstance().Servers)
{
ServerInfo eachServer = new ServerInfo()
@ -220,11 +218,9 @@ namespace IW4MAdmin
currentPlayers = S.GetPlayersAsList().Count,
chatHistory = S.ChatHistory,
players = new List<PlayerInfo>(),
ID = i
PlayerHistory = S.PlayerHistory.ToArray()
};
i++;
bool authed = ApplicationManager.GetInstance().GetPrivilegedClients()
.Where(x => x.IP == querySet["IP"])
.Where(x => x.Level > Player.Permission.Trusted).Count() > 0
@ -701,26 +697,18 @@ namespace IW4MAdmin
public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
List<PageInfo> pages = new List<PageInfo>();
foreach (var p in SharedLibrary.WebService.PageList.Where(x => x.Visible()))
var pages = SharedLibrary.WebService.PageList.Select(p => new
{
if (p == this)
continue;
PageInfo pi = new PageInfo()
{
pagePath = p.GetPath(),
pageName = p.GetName(),
visible = p.Visible()
};
pages.Add(pi);
}
pagePath = p.GetPath(),
pageName = p.GetName(),
visible = p.Visible(),
});
HttpResponse resp = new HttpResponse()
{
contentType = GetContentType(),
content = Newtonsoft.Json.JsonConvert.SerializeObject(pages),
content = Newtonsoft.Json.JsonConvert.SerializeObject(pages.ToArray()),
additionalHeaders = new Dictionary<string, string>()
};
return resp;
@ -846,6 +834,7 @@ namespace IW4MAdmin
public int maxPlayers;
public List<Chat> chatHistory;
public List<PlayerInfo> players;
public SharedLibrary.Helpers.PlayerHistory[] PlayerHistory;
public int ID;
}

Binary file not shown.

View File

@ -1,6 +1,7 @@
</div>
<div id="footer">&copy; RaidMax</div>
</body>
<script src="https://use.fontawesome.com/9c581fe29b.js"></script>
<script>
getPages();
</script>

View File

@ -7,7 +7,6 @@
<link href='https://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://use.fontawesome.com/9c581fe29b.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/canvasjs/1.7.0/canvasjs.min.js"></script>
<link rel="stylesheet" type="text/css" href="/webfront/main.css"/>

View File

@ -1,101 +1,99 @@
<script>
var chartsRendered = false;
function getPlayerHistoryChart(playerHistory, i) {
///////////////////////////////////////
return new CanvasJS.Chart(`graph-player-history-${i}`, {
backgroundColor: "#191919",
height: 100,
animationEnabled: true,
function renderPlayerHistory(id) {
$.getJSON("/_playerhistory?server=" + id, function (playerHistory) {
toolTip: {
contentFormatter: function (e) {
var date = new Date(e.entries[0].dataPoint.x * 1000);
return date.toLocaleTimeString('en-US', { timeZone: 'America/New_York', hour12: true }) + " - " + e.entries[0].dataPoint.y + " players";
}
},
var i = id;
if ($("#server-" + i).children().length > 1)
return false;
axisX: {
interval: 1,
gridThickness: 0,
lineThickness: 0,
tickThickness: 0,
margin: 0,
valueFormatString: " ",
},
$("#server-" + i).append("<div class='player-history' id='graph-player-history-" + i + "'></div><hr/><br/><br/>");
axisY: {
gridThickness: 0,
lineThickness: 0,
tickThickness: 0,
minimum: 0,
margin: 0,
valueFormatString: " ",
labelMaxWidth: 0,
},
///////////////////////////////////////
var chart = new CanvasJS.Chart("graph-player-history-" + i,
{
backgroundColor: "#191919",
height: 100,
animationEnabled: true,
legend: {
maxWidth: 0,
maxHeight: 0,
dockInsidePlotArea: true,
},
toolTip: {
contentFormatter: function (e) {
var date = new Date(e.entries[0].dataPoint.x * 1000);
return date.toLocaleTimeString('en-US', { timeZone: 'America/New_York', hour12: true }) + " - " + e.entries[0].dataPoint.y + " players";
}
},
axisX: {
interval: 1,
gridThickness: 0,
lineThickness: 0,
tickThickness: 0,
margin: 0,
valueFormatString: " ",
},
axisY: {
gridThickness: 0,
lineThickness: 0,
tickThickness: 0,
minimum: 0,
margin: 0,
valueFormatString: " ",
labelMaxWidth: 0,
},
legend: {
maxWidth: 0,
maxHeight: 0,
dockInsidePlotArea: true,
},
data: [{
showInLegend: false,
type: "splineArea",
color: "rgba(0, 122, 204, 0.432)",
markerSize: 0,
dataPoints: playerHistory,
}]
});
chart.render();
//////////////////////////////////////
data: [{
showInLegend: false,
type: "splineArea",
color: "rgba(0, 122, 204, 0.432)",
markerSize: 0,
dataPoints: playerHistory,
}]
});
//////////////////////////////////////
}
function getServers() {
$.getJSON("/_servers", function (result) {
result = result.sort(function (a, b) { return a.currentPlayers < b.currentPlayers });
$.each(result, function (i, server) {
var selectedServer = $(`#server-${i}`);
if ($('#server-' + i).length < 1)
$('#serverList').append("<div id='server-" + i + "'></div>")
if (selectedServer.length < 1) {
$('#serverList').append(`<div id="server-${i}"><div class="serverContainer"></div></div>`);
selectedServer = $(`#server-${i}`);
selectedServer.append(`<div class="player-history" id="graph-player-history-${i}"></div><hr/><br/><br/>`)
}
$('#server-' + i + ' .serverContainer').remove();
$('#server-' + i).prepend("<div class='serverContainer'> \
<div class='serverInfo table'> \
<div class='serverTitle tableCell'>" + server['serverName'] + "</div> \
<div class='serverMap tableCell'>" + server['mapName'] + "</div> \
<div class='serverPlayers tableCell'>" + server['currentPlayers'] + "/" + server['maxPlayers'] + "</div> \
</div> \
<div class='serverChatList table'>" +
formatMessages(server['chatHistory'])
+ "</div> \
<div class='serverPlayerList table'>" +
formatPlayers(server['players'])
+ "</div> \
<div style='clear: both;'></div><hr/></div> \
</div>"
);
renderPlayerHistory(i);
var template =
`
<div class ="serverInfo table">
<div class ="serverTitle tableCell">${server.serverName}</div>
<div class ="serverMap tableCell">${server.mapName}</div>
<div class ="serverPlayers tableCell">${server.currentPlayers}/${server.maxPlayers}</div>
</div>
<div class ="serverChatList table">${formatMessages(server.chatHistory)}</div>
<div class ="serverPlayerList table">${formatPlayers(server.players)}</div>
<div style="clear:both;"></div>
<hr/>`;
selectedServer.find('.serverContainer').html(template);
if (!selectedServer.find(`#graph-player-history-${i}`).children().length) {
var historyGraph = getPlayerHistoryChart(server.PlayerHistory, i);
$(document).trigger("graphready", [historyGraph]);
}
});
});
}
$(document).ready(function () {
getServers();
setInterval(getServers, 1000)
setInterval(getServers, 1000);
});
$(document).on("graphready", function (e, graph) {
// why is this so slow I have to call it async?
setTimeout(graph.render, 1);
})
</script>
<div id="serverList">
</div>

View File

@ -7,6 +7,7 @@
<script>
var killsList = [];
var refreshInterval = 250;
function drawCircle(context, x, y, color) {
context.beginPath();
@ -100,7 +101,10 @@
checkCanvasSize(canvas, canvas[0].getContext("2d"), minimap, server.Minimap[0]);
var furthestKill = 0;
$.each(newKills, function (i, kill) {
if (kill.Distance > furthestKill)
furthestKill = kill.Distance;
drawKill('1', canvas, server, kill);
});
@ -112,23 +116,31 @@
var html = '<span>' + server.ServerInfo.Uptime + ' of uptime</span><br/><span>Round started ' + server.ServerInfo.ElapsedRoundTime + '</span><br/>';
html += '<span>Furthest kill from ' + Math.round(furthestKill * 10) / 10 + ' meters</span><br/>';
if (newKills.length > 0)
html += '<span class="last-kill">' + newKills[0].KillerPlayer + ' killed ' + newKills[0].VictimPlayer + '</span><br/>';
if (newKills.length > 0) {
if (newKills[0].KillerPlayer != null)
html += '<span class="last-kill">' + newKills[0].KillerPlayer + ' killed ' + newKills[0].VictimPlayer + '</span><br/>';
else
html += `<span class="last-kill">Kill information pulled from database</span><br/>`;
}
else
html += '<span class="last-kill">' + $('#stats-container-' + i).find('.last-kill').text() + '</span><br/>';
$('#stats-container-' + i + ' .stats-serverinfo').html(html);
});
});
setTimeout(loadKills, refreshInterval)
}
$(document).ready(function () {
$('#KillEventCount').on('input change', function () {
$(this).next().text('Showing ' + $(this).val() + ' Kills');
if ($(this).val() > 300)
refreshInterval = 500;
else
refreshInterval = 250;
});
loadKills();
setInterval(loadKills, 1000);
});
</script>

View File

@ -268,7 +268,7 @@ namespace StatsPlugin
CalculateAndSaveSkill(P, statLists.Find(x => x.Port == S.GetPort()));
ResetCounters(P.ClientID, S.GetPort());
E.Owner.Logger.WriteInfo("Updated skill for client #" + P.DatabaseID);
E.Owner.Logger.WriteInfo($"Updated skill for {P}");
//E.Owner.Log.Write(String.Format("\r\nJoin: {0}\r\nInactive Minutes: {1}\r\nnewPlayTime: {2}\r\nnewSPM: {3}\r\nkdrWeight: {4}\r\nMultiplier: {5}\r\nscoreWeight: {6}\r\nnewSkillFactor: {7}\r\nprojectedNewSkill: {8}\r\nKills: {9}\r\nDeaths: {10}", connectionTime[P.clientID].ToShortTimeString(), inactiveMinutes[P.clientID], newPlayTime, newSPM, kdrWeight, Multiplier, scoreWeight, newSkillFactor, disconnectStats.Skill, disconnectStats.Kills, disconnectStats.Deaths));
}
}
@ -311,6 +311,7 @@ namespace StatsPlugin
ServerStats[S.GetPort()].GetKillQueue().Enqueue(killEvent);
//S.Logger.WriteInfo($"{E.Origin.Name} killed {E.Target.Name} with a {killEvent.Weapon} from a distance of {Vector3.Distance(killEvent.KillOrigin, killEvent.DeathOrigin)} with {killEvent.Damage} damage, at {killEvent.HitLoc}");
curServer.playerStats.AddKill(killEvent);
S.Logger.WriteInfo(killEvent.ID.ToString());
return;
}
@ -521,10 +522,10 @@ namespace StatsPlugin
return resultList;
}
public List<Stats.KillInfo> GetKillsByMap(Map map)
public List<Stats.KillInfo> GetKillsByMap(Map map, int count)
{
var mapID = ParseEnum<IW4Info.MapName>.Get(map.Name, typeof(IW4Info.MapName));
var queryResult = GetDataTable($"select * from KILLS where MapID == {(int)mapID} LIMIT 500 OFFSET (SELECT COUNT(*) FROM KILLS)-500"); //GetDataTable("KILLS", new KeyValuePair<string, object>("MapID", mapID));
var queryResult = GetDataTable($"select * from KILLS where MapID == {(int)mapID} LIMIT {count} OFFSET (SELECT COUNT(*) FROM KILLS)-500"); //GetDataTable("KILLS", new KeyValuePair<string, object>("MapID", mapID));
var resultList = new List<Stats.KillInfo>();
if (queryResult?.Rows.Count > 0)

View File

@ -55,8 +55,9 @@ namespace StatsPlugin
ServerMap = s.CurrentMap.Alias,
ServerInfo = Stats.ServerStats[s.GetPort()],
Minimap = MinimapConfig.Read(@"Config\minimaps.cfg").MapInfo.Where(m => m.MapName == s.CurrentMap.Name),
MapKills = Stats.ServerStats[s.GetPort()].GetKillQueue().ToArray()
.Skip(Math.Min(Stats.MAX_KILLEVENTS - selectCount, Stats.ServerStats[s.GetPort()].GetKillQueue().Count - selectCount))
MapKills = selectCount < 300 ? Stats.ServerStats[s.GetPort()].GetKillQueue().ToArray()
.Skip(Math.Min(Stats.MAX_KILLEVENTS - selectCount, Stats.ServerStats[s.GetPort()].GetKillQueue().Count - selectCount)) :
Stats.statLists.FirstOrDefault(x => x.Port == s.GetPort()).playerStats.GetKillsByMap(s.CurrentMap, selectCount)
})
},
additionalHeaders = new Dictionary<string, string>()

View File

@ -74,14 +74,17 @@ namespace IW4MAdmin.Plugins
string[] eventLine = null;
if (S.GameName == Server.Game.IW4)
for (int i = 0; i < 1; i++)
{
// attackerID ; victimID ; attackerOrigin ; victimOrigin ; Damage ; Weapon ; hitLocation ; meansOfDeath
var minimapInfo = StatsPlugin.MinimapConfig.IW4Minimaps().MapInfo.FirstOrDefault(m => m.MapName == S.CurrentMap.Name);
if (minimapInfo == null)
return;
eventLine = new string[]
if (S.GameName == Server.Game.IW4)
{
// attackerID ; victimID ; attackerOrigin ; victimOrigin ; Damage ; Weapon ; hitLocation ; meansOfDeath
var minimapInfo = StatsPlugin.MinimapConfig.IW4Minimaps().MapInfo.FirstOrDefault(m => m.MapName == S.CurrentMap.Name);
if (minimapInfo == null)
return;
eventLine = new string[]
{
"ScriptKill",
attackerPlayer.NetworkID,
victimPlayer.NetworkID,
@ -91,13 +94,13 @@ namespace IW4MAdmin.Plugins
((StatsPlugin.IW4Info.WeaponName)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.WeaponName)).Length - 1)).ToString(),
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(),
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString()
};
}
};
else
{
eventLine = new string[]
{
}
else
{
eventLine = new string[]
{
"K",
victimPlayer.NetworkID,
victimPlayer.ClientID.ToString(),
@ -111,11 +114,12 @@ namespace IW4MAdmin.Plugins
rand.Next(50, 105).ToString(), // Damage
((StatsPlugin.IW4Info.MeansOfDeath)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.MeansOfDeath)).Length - 1)).ToString(), // Means of Death
((StatsPlugin.IW4Info.HitLocation)rand.Next(0, Enum.GetValues(typeof(StatsPlugin.IW4Info.HitLocation)).Length - 1)).ToString(), // Hit Location
};
}
};
}
var _event = Event.ParseEventString(eventLine, S);
await S.ExecuteEvent(_event);
var _event = Event.ParseEventString(eventLine, S);
await S.ExecuteEvent(_event);
}
}
}