1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-11 15:52:25 -05:00

-added back player history graphs (past 12 hours every 15 minutes)

-fixed issue with configurationmanager files and threading
-servers on webfront listed in descending player count
-fixed resolution of tempban times from console feedback
-Added tests plugin to simulate functionality
This commit is contained in:
RaidMax
2017-09-27 15:07:43 -05:00
parent 9227335d25
commit 8d52d7ddc5
21 changed files with 470 additions and 127 deletions

View File

@ -174,9 +174,6 @@
<Content Include="webfront\footer.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\graph.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\header.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@ -187,7 +184,7 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="webfront\main.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="webfront\mobile.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

View File

@ -69,7 +69,10 @@ namespace IW4MAdmin
catch (Exception e)
{
ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request: {e.Message}");
ApplicationManager.GetInstance().Logger.WriteError($"Webfront error during request");
ApplicationManager.GetInstance().Logger.WriteDebug($"Message: {e.Message}");
ApplicationManager.GetInstance().Logger.WriteDebug($"Stack Trace: {e.StackTrace}");
response.OnResponse(new HttpResponseHead()
{
Status = "500 Internal Server Error",

View File

@ -28,6 +28,7 @@ namespace IW4MAdmin
List<MessageToken> MessageTokens;
Kayak.IScheduler webServiceTask;
Thread WebThread;
List<Player> PrivilegedClients;
#if FTP_LOG
const int UPDATE_FREQUENCY = 15000;
#else
@ -179,11 +180,17 @@ namespace IW4MAdmin
WebThread.Start();
#endregion
#region ADMINS
PrivilegedClients = GetClientDatabase().GetAdmins();
#endregion
Running = true;
}
public void Start()
{
var a = Utilities.DateTimeSQLite(DateTime.MinValue);
while (Running)
{
for (int i = 0; i < TaskStatuses.Count; i++)
@ -197,7 +204,7 @@ namespace IW4MAdmin
}
}
Thread.Sleep(300);
Thread.Sleep(UPDATE_FREQUENCY);
}
#if !DEBUG
foreach (var S in Servers)
@ -277,6 +284,11 @@ namespace IW4MAdmin
return allAliases;
}
public IList<Player> GetPrivilegedClients()
{
return PrivilegedClients;
}
private void GetAliases(List<Aliases> returnAliases, Aliases currentAlias)
{
foreach (String IP in currentAlias.IPS)

View File

@ -291,6 +291,9 @@ namespace IW4MAdmin
async Task<int> PollPlayersAsync()
{
#if DEBUG
return Players.Where(p => p != null).Count();
#endif
var CurrentPlayers = await this.GetStatusAsync();
for (int i = 0; i < Players.Count; i++)
@ -357,15 +360,15 @@ namespace IW4MAdmin
tickTime = DateTime.Now;
}
if ((lastCount - playerCountStart).TotalMinutes > 4)
if ((lastCount - playerCountStart).TotalMinutes >= 15)
{
while (PlayerHistory.Count > 144) // 12 times a minute for 12 hours
while (PlayerHistory.Count > 48) // 4 times a hour for 12 hours
PlayerHistory.Dequeue();
PlayerHistory.Enqueue(new SharedLibrary.Helpers.PlayerHistory(lastCount, ClientNum));
PlayerHistory.Enqueue(new SharedLibrary.Helpers.PlayerHistory(ClientNum));
playerCountStart = DateTime.Now;
}
if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 /*&& ClientNum > 0*/)
if (LastMessage.TotalSeconds > MessageTime && BroadcastMessages.Count > 0 && ClientNum > 0)
{
await Broadcast(Utilities.ProcessMessageToken(Manager.GetMessageTokens(), BroadcastMessages[NextMessage]));
NextMessage = NextMessage == (BroadcastMessages.Count - 1) ? 0 : NextMessage + 1;
@ -489,7 +492,7 @@ namespace IW4MAdmin
}
#if DEBUG
basepath.Value = (GameName == Game.IW4) ?
@"\\tsclient\K\MW2" :
@"\\tsclient\J\WIN7_10.25\MW2" :
@"\\tsclient\G\Program Files (x86)\Steam\SteamApps\common\Call of Duty 4";
#endif
string mainPath = (GameName == Game.IW4) ? "userraw" : "main";

View File

@ -22,6 +22,7 @@ namespace IW4MAdmin
SharedLibrary.WebService.PageList.Add(new Pages());
SharedLibrary.WebService.PageList.Add(new Homepage());
SharedLibrary.WebService.PageList.Add(new ServersJSON());
SharedLibrary.WebService.PageList.Add(new PlayerHistoryJSON());
SharedLibrary.WebService.PageList.Add(new Penalties());
SharedLibrary.WebService.PageList.Add(new PenaltiesJSON());
SharedLibrary.WebService.PageList.Add(new Players());
@ -57,7 +58,7 @@ namespace IW4MAdmin
catch (Exception e)
{
ApplicationManager.GetInstance().Logger.WriteError($"Unable to start webservice ( port is probably in use ): {e.Message}");
ApplicationManager.GetInstance().Logger.WriteError($"Unable to start webservice ( port is probably in use ): {e.Message}");
}
}
@ -196,6 +197,7 @@ namespace IW4MAdmin
{
var info = new List<ServerInfo>();
int i = 0;
foreach (Server S in ApplicationManager.GetInstance().Servers)
{
ServerInfo eachServer = new ServerInfo()
@ -207,10 +209,16 @@ namespace IW4MAdmin
gameType = Utilities.GetLocalizedGametype(S.Gametype),
currentPlayers = S.GetPlayersAsList().Count,
chatHistory = S.ChatHistory,
players = new List<PlayerInfo>()
players = new List<PlayerInfo>(),
ID = i
};
bool authed = ApplicationManager.GetInstance().GetClientDatabase().GetAdmins().FindAll(x => x.IP == querySet["IP"] && x.Level > Player.Permission.Trusted).Count > 0
|| querySet["IP"] == "127.0.0.1";
i++;
bool authed = ApplicationManager.GetInstance().GetPrivilegedClients()
.Where(x => x.IP == querySet["IP"])
.Where(x => x.Level > Player.Permission.Trusted).Count() > 0
|| querySet["IP"] == "127.0.0.1";
foreach (Player P in S.GetPlayersAsList())
{
@ -226,7 +234,6 @@ namespace IW4MAdmin
info.Add(eachServer);
}
HttpResponse resp = new HttpResponse()
{
contentType = GetContentType(),
@ -247,6 +254,54 @@ namespace IW4MAdmin
}
}
class PlayerHistoryJSON : IPage
{
public string GetName()
{
return "Player History";
}
public string GetPath()
{
return "/_playerhistory";
}
public HttpResponse GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
{
var history = new SharedLibrary.Helpers.PlayerHistory[0];
try
{
int id = Int32.Parse(querySet["server"]);
history = ApplicationManager.GetInstance().GetServers()[id].PlayerHistory.ToArray();
}
catch (Exception)
{
}
HttpResponse resp = new HttpResponse()
{
contentType = GetContentType(),
content = Newtonsoft.Json.JsonConvert.SerializeObject(history),
additionalHeaders = new Dictionary<string, string>()
};
return resp;
}
public string GetContentType()
{
return "application/json";
}
public bool Visible()
{
return false;
}
}
class Info : IPage
{
public string GetName()
@ -412,7 +467,8 @@ namespace IW4MAdmin
penaltyTime = Utilities.GetTimePassed(p.When),
penaltyType = p.BType.ToString(),
playerName = penalized.Name,
playerID = penalized.DatabaseID
playerID = penalized.DatabaseID,
Expires = p.Expires > DateTime.Now ? (p.Expires - DateTime.Now).TimeSpanText() : ""
};
if (admin.NetworkID == penalized.NetworkID)
@ -644,7 +700,7 @@ namespace IW4MAdmin
PageInfo pi = new PageInfo()
{
pagePath = p.GetPath(),
pagePath = p.GetPath(),
pageName = p.GetName(),
visible = p.Visible()
};
@ -670,7 +726,7 @@ namespace IW4MAdmin
return false;
}
}
class GetPlayer : IPage
{
public string GetContentType()
@ -718,7 +774,7 @@ namespace IW4MAdmin
else if (querySet["recent"] != null)
{
matchedPlayers = ApplicationManager.GetInstance().GetClientDatabase().GetRecentPlayers();
matchedPlayers = ApplicationManager.GetInstance().GetClientDatabase().GetRecentPlayers();
recent = true;
}
@ -780,6 +836,7 @@ namespace IW4MAdmin
public int maxPlayers;
public List<Chat> chatHistory;
public List<PlayerInfo> players;
public int ID;
}
[Serializable]
@ -825,6 +882,7 @@ namespace IW4MAdmin
public string penaltyType;
public string penaltyReason;
public string penaltyTime;
public string Expires;
}
[Serializable]

Binary file not shown.

View File

@ -1,4 +1,11 @@
VERSION 1.4
Versino 1.5
CHANGELOG:
-added back player history graphs (past 12 hours every 15 minutes)
-fixed issue with configurationmanager files and threading
-servers on webfront listed in descending player count
-fixed resolution of tempban times from console feedback
VERSION 1.4
CHANGELOG:
-works: with COD, WaW, MW3, BO1 (preliminary without extensive testing)
-fixed the issue with webfront chat history

View File

@ -1,58 +0,0 @@
<script type="text/javascript" src="//www.google.com/jsapi"></script>
<script>
google.load('visualization', '1', { callback: drawChart, packages: ['corechart'] });
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Players');
data.addRows(players);
var options = {
//curveType: 'function', still haven't decided on this
height: 300,
legend: {position: 'none'},
enableInteractivity: true,
chartArea: {
width: '93%'
},
vAxis: {
title: 'Players',
gridlines: { count: 7 },
viewWindowMode: 'explicit',
viewWindow: {
min: 0,
max: 18 // for iw4
},
},
hAxis: {
viewWindow: {
//min: players[0][0], no longer needed as timeline adjusts automatically
//max: players[players.length-1][0] // ditto
},
gridlines: {
count: 12,
units: {
days: {format: ["MMM dd"]},
hours: {format: ["HH:mm", "ha"]},
}
},
minorGridlines: {
count: 5,
units: {
hours: {format: ["hh:mm:ss a", "ha"]},
minutes: {format: ["HH:mm a Z", ":mm"]}
}
}
}
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
{{GRAPH}}

View File

@ -8,6 +8,7 @@
<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"/>
<link rel="stylesheet" type="text/css" href="/webfront/mobile.css"/>

View File

@ -15,7 +15,7 @@ div#header #navContainer .navEntry a { padding: 1.2vw; width: 4vw; }
div#header #navContainer .navEntry:hover { background-color: rgb(34, 34, 34); }
div#content { margin: 3em 10%; }
div#content .serverContainer { background-color: #191919; margin: 2em 0; font-size: 1.25vw; }
div#content .serverContainer { background-color: #191919; margin-top 0; margin-bottom: 0; font-size: 1.25vw; padding-bottom: 100px; }
div#content hr { border-width: 0; height: 0.25em; background-color: #007ACC; }
div#content .serverInfo { width: 100%; }
div#content .serverInfo .tableCell { padding: 0 0.5em; }
@ -31,13 +31,15 @@ div#content .chatPlayerName { font-weight: bold; font-size: 1.1vw; color:#fff; p
div#content .chatPlayerMessage {font-size: 1.1vw; color: #fff; opacity: 1; }
div#content .playerPenalty, div#content .playerInfo { margin: 0 auto; padding: 1em 10px; background-color: #181818; width: calc(100% - 20px); }
div#content .penaltyName { width: 14.28%; }
div#content .penaltyName { width: 15%; }
div#content .penaltyName a:link, div#content .penaltyName a:visited, div#content .playerInfo a:link, div#content .playerInfo a:visited { color: rgb(0, 122, 204) !important; }
div#content .penaltyName a:hover, div#content .playerInfo a:hover { color: rgb(255, 255, 255) !important; opacity: 0.75; }
div#content .penaltyTime { text-align: right; width: 12.5%; }
div#content .penaltyTime { text-align: left; width:8%; }
div#content .penaltyOrigin {width: 12%;}
div#content .penaltyRemaining { text-align: right; width: 10%:}
div#content .playerPenalty .penaltyTime { opacity: 0.5; }
div#content .penaltyType { width: 12.5%; }
div#content .penaltyReason { width: 50%; }
div#content .penaltyType { width: 10%; }
div#content .penaltyReason { width: 45%; }
div#content .playerPenalty .tableCell { }
div#content .penaltyHeader, div#content .contentHeader { width: calc(100% - 20px); background-color: #007ACC; font-size: 15pt; padding: 0.5em 10px; }
div#content .alternate_1 { background-color: rgb(34, 34, 34); }
@ -199,3 +201,5 @@ div#footer { position: fixed; bottom: 0.5em; right: 0.5em; opacity: 0.5; }
.admin-name a { font-size: 14pt; color: #007ACC !important; }
.admin-name a:hover { color: #fff !important; }
.clients { margin: 0.5em; }
.canvasjs-chart-credit { display: none; }
.player-history { margin-top: -100px; height: 100px; }

View File

@ -1,31 +1,101 @@
<script>
function getServers()
{
$.getJSON("/_servers", function(result){
$("#serverList").html("");
$.each(result, function(i, server){
$("#serverList").append("<div class=serverContainer> \
var chartsRendered = false;
function renderPlayerHistory(id) {
$.getJSON("/_playerhistory?server=" + id, function (playerHistory) {
var i = id;
if ($("#server-" + i).children().length > 1)
return false;
$("#server-" + i).append("<div class='player-history' id='graph-player-history-" + i + "'></div><hr/><br/><br/>");
///////////////////////////////////////
var chart = new CanvasJS.Chart("graph-player-history-" + i,
{
backgroundColor: "#191919",
height: 100,
animationEnabled: 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();
//////////////////////////////////////
});
}
function getServers() {
$.getJSON("/_servers", function (result) {
result = result.sort(function (a, b) { return a.currentPlayers < b.currentPlayers });
$.each(result, function (i, server) {
if ($('#server-' + i).length < 1)
$('#serverList').append("<div id='server-" + i + "'></div>")
$('#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> \
formatMessages(server['chatHistory'])
+ "</div> \
<div class='serverPlayerList table'>" +
formatPlayers(server['players'])
+ "</div> \
<div style='clear: both;'></div><hr/></div>"
);
});
});
}
formatPlayers(server['players'])
+ "</div> \
<div style='clear: both;'></div><hr/></div> \
</div>"
);
renderPlayerHistory(i);
});
});
}
$( document ).ready(function() {
getServers();
setInterval(getServers, 1000)
});
$(document).ready(function () {
getServers();
setInterval(getServers, 1000)
});
</script>
<div id="serverList">
</div>

View File

@ -34,6 +34,7 @@ function getPenalties(from)
<div class=\"penaltyReason tableCell\">"+ penalty['penaltyReason'] + "</div> \
<div class=\"penaltyOrigin tableCell\">"+ getColorForLevel(penalty['adminLevel'], penalty['adminName']) + "</div> \
<div class=\"penaltyTime tableCell\">"+ penalty['penaltyTime'] + "</div> \
<div class=\" penaltyRemaining tableCell\">" + penalty['Expires'] + "</div> \
</div>"
)
});
@ -51,6 +52,7 @@ $( document ).ready(function() {
<div class="penaltyReason tableCell">Reason</div>
<div class="penaltyOrigin tableCell">Admin</div>
<div class="penaltyTime tableCell">Time</div>
<div class="penaltyRemaining tableCell">Remaining</div>
</div>
<div id="penaltyList">
</div>