public async Task <IActionResult> GetMessageAsync(string serverId, long when) { var whenTime = DateTime.FromFileTimeUtc(when); var whenUpper = whenTime.AddMinutes(5); var whenLower = whenTime.AddMinutes(-5); var messages = await _chatResourceQueryHelper.QueryResource(new ChatSearchQuery() { ServerId = serverId, SentBefore = whenUpper, SentAfter = whenLower }); return(View("~/Views/Client/_MessageContext.cshtml", messages.Results.ToList())); }
public async Task <IActionResult> FindAsync([FromQuery] FindClientRequest request) { if (!ModelState.IsValid) { return(BadRequest(new ErrorResponse() { Messages = ModelState.Values.SelectMany(_value => _value.Errors.Select(_error => _error.ErrorMessage)).ToArray() })); } try { var results = await _clientQueryHelper.QueryResource(request); return(Ok(new FindClientResponse { TotalFoundClients = results.TotalResultCount, Clients = results.Results })); } catch (Exception e) { _logger.WriteWarning($"Failed to retrieve clients with query - {request.ToDebugString()}"); _logger.WriteDebug(e.GetExceptionInfo()); return(StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse() { Messages = new[] { e.Message } })); } }
public async Task Test_StatsController_ClientStats_Happy() { var client = ClientGenerators.CreateBasicClient(null); var query = new StatsInfoRequest { ClientId = client.ClientId }; var queryResult = new ResourceQueryHelperResult <StatsInfoResult>() { Results = new[] { new StatsInfoResult { Deaths = 1, Kills = 1, LastPlayed = DateTime.Now, Performance = 100, Ranking = 10, ScorePerMinute = 500, ServerGame = "IW4", ServerId = 123, ServerName = "IW4Host", TotalSecondsPlayed = 100 } }, TotalResultCount = 1, RetrievedResultCount = 1 }; A.CallTo(() => fakeStatsQueryHelper.QueryResource(A <StatsInfoRequest> .Ignored)) .Returns(Task.FromResult(queryResult)); var result = await statsController.ClientStats(query.ClientId.Value); Assert.IsInstanceOf <OkObjectResult>(result); var viewResult = (result as OkObjectResult).Value as IEnumerable <StatsInfoResult>; Assert.NotNull(viewResult); Assert.AreEqual(queryResult.Results, viewResult); }
public async Task <IActionResult> Advanced(int id, [FromQuery] string serverId) { ViewBag.Config = _defaultConfig.GameStrings; var hitInfo = await _queryHelper.QueryResource(new StatsInfoRequest { ClientId = id, ServerEndpoint = serverId }); return(View("~/Views/Client/Statistics/Advanced.cshtml", hitInfo.Results.First())); }
public async Task <IActionResult> ClientStats(int clientId) { if (clientId < 1 || !ModelState.IsValid) { return(BadRequest(new ErrorResponse { Messages = new[] { $"Client Id must be between 1 and {int.MaxValue}" } })); } var request = new StatsInfoRequest() { ClientId = clientId }; try { var result = await _statsQueryHelper.QueryResource(request); if (result.RetrievedResultCount == 0) { return(NotFound()); } return(Ok(result.Results)); } catch (Exception e) { _logger.WriteWarning($"Could not get client stats for client id {clientId}"); _logger.WriteDebug(e.GetExceptionInfo()); return(StatusCode(StatusCodes.Status500InternalServerError, new ErrorResponse { Messages = new[] { e.Message } })); } }
private async Task <IEnumerable <ConnectionHistoryResponse> > GetConnectionHistoryMeta(ClientPaginationRequest request) { var connections = await _connectionHistoryHelper.QueryResource(request); return(connections.Results); }
private async Task <IEnumerable <UpdatedAliasResponse> > GetUpdatedAliasMeta(ClientPaginationRequest request) { var aliases = await _updatedAliasHelper.QueryResource(request); return(aliases.Results); }
private async Task <IEnumerable <AdministeredPenaltyResponse> > GetAdministeredPenaltiesMeta(ClientPaginationRequest request) { var penalties = await _administeredPenaltyHelper.QueryResource(request); return(penalties.Results); }
public async Task OnLoadAsync(IManager manager) { // load custom configuration if (Config.Configuration() == null) { Config.Set((StatsConfiguration) new StatsConfiguration().Generate()); } Config.Configuration().ApplyMigration(); await Config.Save(); // register the topstats page // todo:generate the URL/Location instead of hardcoding manager.GetPageList() .Pages.Add( Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_TOP_TEXT"], "/Stats/TopPlayersAsync"); // meta data info async Task <IEnumerable <InformationResponse> > getStats(ClientPaginationRequest request) { IList <EFClientStatistics> clientStats; int messageCount = 0; await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false); clientStats = await ctx.Set <EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync(); messageCount = await ctx.Set <EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId); int kills = clientStats.Sum(c => c.Kills); int deaths = clientStats.Sum(c => c.Deaths); double kdr = Math.Round(kills / (double)deaths, 2); var validPerformanceValues = clientStats.Where(c => c.Performance > 0); int performancePlayTime = validPerformanceValues.Sum(s => s.TimePlayed); double performance = Math.Round(validPerformanceValues.Sum(c => c.Performance * c.TimePlayed / performancePlayTime), 2); double spm = Math.Round(clientStats.Sum(c => c.SPM) / clientStats.Where(c => c.SPM > 0).Count(), 1); return(new List <InformationResponse>() { new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"], Value = "#" + (await Manager.GetClientOverallRanking(request.ClientId)).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 0, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"], Value = kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 1, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_DEATHS"], Value = deaths.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 2, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"], Value = kdr.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 3, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_PERFORMANCE"], Value = performance.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 4, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_META_SPM"], Value = spm.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 0, Order = 5, Type = MetaType.Information }, new InformationResponse() { Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"], Value = messageCount.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Column = 1, Order = 4, Type = MetaType.Information } }); } async Task <IEnumerable <InformationResponse> > getAnticheatInfo(ClientPaginationRequest request) { IList <EFClientStatistics> clientStats; await using var ctx = _databaseContextFactory.CreateContext(enableTracking: false); clientStats = await ctx.Set <EFClientStatistics>() .Include(c => c.HitLocations) .Where(c => c.ClientId == request.ClientId) .ToListAsync(); double headRatio = 0; double chestRatio = 0; double abdomenRatio = 0; double chestAbdomenRatio = 0; double hitOffsetAverage = 0; double averageSnapValue = 0; double maxStrain = clientStats.Count(c => c.MaxStrain > 0) == 0 ? 0 : clientStats.Max(cs => cs.MaxStrain); if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null) { chestRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.First(hl => hl.Location == (int)IW4Info.HitLocation.torso_upper).HitCount) / (double)clientStats.Where(c => c.HitLocations.Count > 0) .Sum(c => c.HitLocations.Where(hl => hl.Location != (int)IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0); abdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.First(hl => hl.Location == (int)IW4Info.HitLocation.torso_lower).HitCount) / (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.Where(hl => hl.Location != (int)IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0); chestAbdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == (int)IW4Info.HitLocation.torso_upper).HitCount) / (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == (int)IW4Info.HitLocation.torso_lower).HitCount)) * 100.0, 0); headRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == (int)IW4Info.HitLocation.head).HitCount) / (double)clientStats.Where(c => c.HitLocations.Count > 0) .Sum(c => c.HitLocations.Where(hl => hl.Location != (int)IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0); var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations); hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount); averageSnapValue = clientStats.Any(_stats => _stats.AverageSnapValue > 0) ? clientStats.Where(_stats => _stats.AverageSnapValue > 0).Average(_stat => _stat.AverageSnapValue) : 0; } return(new List <InformationResponse>() { new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 1", Value = chestRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%', Type = MetaType.Information, Column = 2, Order = 0, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM1"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 2", Value = abdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%', Type = MetaType.Information, Column = 2, Order = 1, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM2"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 3", Value = chestAbdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%', Type = MetaType.Information, Column = 2, Order = 2, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM3"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 4", Value = headRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%', Type = MetaType.Information, Column = 2, Order = 3, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM4"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 5", // todo: make sure this is wrapped somewhere else Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°", Type = MetaType.Information, Column = 2, Order = 4, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM5"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 6", Value = Math.Round(maxStrain, 3).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Type = MetaType.Information, Column = 2, Order = 5, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM6"], IsSensitive = true }, new InformationResponse() { Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 7", Value = Math.Round(averageSnapValue, 3).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)), Type = MetaType.Information, Column = 2, Order = 6, ToolTipText = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM7"], IsSensitive = true } }); } async Task <IEnumerable <MessageResponse> > getMessages(ClientPaginationRequest request) { var query = new ChatSearchQuery() { ClientId = request.ClientId, Before = request.Before, SentBefore = request.Before ?? DateTime.UtcNow, Count = request.Count, IsProfileMeta = true }; return((await _chatQueryHelper.QueryResource(query)).Results); } if (Config.Configuration().AnticheatConfiguration.Enable) { _metaService.AddRuntimeMeta <ClientPaginationRequest, InformationResponse>(MetaType.Information, getAnticheatInfo); } _metaService.AddRuntimeMeta <ClientPaginationRequest, InformationResponse>(MetaType.Information, getStats); _metaService.AddRuntimeMeta <ClientPaginationRequest, MessageResponse>(MetaType.ChatMessage, getMessages); async Task <string> totalKills(Server server) { await using var context = _databaseContextFactory.CreateContext(false); long kills = await context.Set <EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalKills); return(kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))); } async Task <string> totalPlayTime(Server server) { await using var context = _databaseContextFactory.CreateContext(false); long playTime = await context.Set <EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalPlayTime); return((playTime / 3600.0).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))); } async Task <string> topStats(Server s) { // todo: this needs to needs to be updated when we DI the lookup return(string.Join(Environment.NewLine, await Commands.TopStats.GetTopStats(s, Utilities.CurrentLocalization.LocalizationIndex))); } async Task <string> mostPlayed(Server s) { // todo: this needs to needs to be updated when we DI the lookup return(string.Join(Environment.NewLine, await Commands.MostPlayedCommand.GetMostPlayed(s, Utilities.CurrentLocalization.LocalizationIndex, _databaseContextFactory))); } async Task <string> mostKills(Server gameServer) { return(string.Join(Environment.NewLine, await Commands.MostKillsCommand.GetMostKills(StatManager.GetIdForServer(gameServer), Config.Configuration(), _databaseContextFactory, _translationLookup))); } manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills)); manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", totalPlayTime)); manager.GetMessageTokens().Add(new MessageToken("TOPSTATS", topStats)); manager.GetMessageTokens().Add(new MessageToken("MOSTPLAYED", mostPlayed)); manager.GetMessageTokens().Add(new MessageToken("MOSTKILLS", mostKills)); if (Config.Configuration().EnableAdvancedMetrics) { foreach (var calculator in _statCalculators) { await calculator.GatherDependencies(); } } ServerManager = manager; Manager = new StatManager(_managerLogger, manager, _databaseContextFactory, Config, _serverDistributionCalculator); await _serverDistributionCalculator.Initialize(); }