Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per server leaderboards #46

Merged
merged 2 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ReplayBrowser/Pages/Changelog.razor
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<li>Added a new contributors page.</li>
<li>Improved speed on the entire site by a whole bunch.</li>
<li>Added a favicon</li>
<li>Added per server leaderboards</li>
</ul>
<p>12.08.2024</p>
<ul>
Expand Down
67 changes: 64 additions & 3 deletions ReplayBrowser/Pages/Leaderboard.razor
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
@page "/leaderboard"
@using Microsoft.AspNetCore.Components.Authorization
@using ReplayBrowser.Data
@using ReplayBrowser.Models
@using ReplayBrowser.Services
@using Microsoft.AspNetCore.Components.Web
@using ReplayBrowser.Helpers
@using ReplayBrowser.Pages.Shared

@inject NavigationManager NavigationManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject IConfiguration Configuration
Expand Down Expand Up @@ -58,8 +58,40 @@ else
id="search"
value="@username"
>
<button class="btn btn-outline-success" type="button" onclick="search()">Filter</button>
</div>
<br/>
<button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#serverSelectionCollapse" aria-expanded="false" aria-controls="serverSelectionCollapse">
Toggle server selection
</button>

<div class="collapse" id="serverSelectionCollapse">
<div style="flex-direction: column; display: flex">
@{
var urls = Configuration.GetSection("ReplayUrls").Get<StorageUrl[]>()!;
var selectedServersQuery = queryDictionary["selectedServers"];
if (selectedServersQuery == null)
{
selectedServersQuery = urls.Select(x => x.FallBackServerName).Aggregate((x, y) => $"{x},{y}");
}

var selectedServers = selectedServersQuery.Split(',');
foreach (var storage in urls)
{
// Server selection
<input
type="checkbox"
class="server-checkbox"
id="@storage.FallBackServerName.Replace(' ', '_')"
name="@storage.FallBackServerName.Replace(' ', '_')"
value="@storage.FallBackServerName"
checked="@selectedServers.Contains(storage.FallBackServerName)"
>
<label for="@storage.FallBackServerName.Replace(' ', '_')">@storage.FallBackServerName (@storage.FallBackServerId)</label>
}
}
</div>
</div>
<button class="btn btn-outline-success" type="button" onclick="search()">Filter</button>
</div>

<hr/>
Expand Down Expand Up @@ -125,10 +157,22 @@ else
}

<script>
const allServersCount = document.getElementsByClassName("server-checkbox").length;

function changeTimeRange(timeRange) {
var uri = new URL(window.location.href);
uri.searchParams.set("timeRange", timeRange);
uri.searchParams.set("username", document.getElementById("search").value);
// Get the selected servers
let selectedServers = Array.from(document.getElementsByClassName("server-checkbox"))
.filter(x => x.checked)
.map(x => x.value)
.join(",");
// If we have all servers selected, we don't need to add the query parameter
if (selectedServers.split(',').length !== allServersCount)
{
uri.searchParams.set("selectedServers", selectedServers);
}
window.location.href = uri.toString();
}

Expand All @@ -137,6 +181,14 @@ else
var uri = new URL(window.location.href);
uri.searchParams.set("timeRange", uri.searchParams.get("timeRange") || 5);
uri.searchParams.set("username",search);
let selectedServers = Array.from(document.getElementsByClassName("server-checkbox"))
.filter(x => x.checked)
.map(x => x.value)
.join(",");
if (selectedServers.split(',').length !== allServersCount)
{
uri.searchParams.set("selectedServers", selectedServers);
}
window.location.href = uri.toString();
}

Expand All @@ -150,6 +202,7 @@ else

$('#search').autocomplete()
});

</script>

<style>
Expand Down Expand Up @@ -197,7 +250,15 @@ else
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
try
{
leaderboard = await LeaderboardService.GetLeaderboard(timeRangeEnum, username, authState);
var selectedServers = queryDictionary["selectedServers"];
if (selectedServers == null)
{
var urls = Configuration.GetSection("ReplayUrls").Get<StorageUrl[]>()!;
selectedServers = urls.Select(x => x.FallBackServerName).Aggregate((x, y) => $"{x},{y}");
}

var selectedServersArray = selectedServers.Split(',');
leaderboard = await LeaderboardService.GetLeaderboard(timeRangeEnum, username, selectedServersArray, authState);
}
catch (UnauthorizedAccessException)
{
Expand Down
26 changes: 21 additions & 5 deletions ReplayBrowser/Services/LeaderboardService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ public class LeaderboardService : IHostedService, IDisposable
private readonly Ss14ApiHelper _apiHelper;
private readonly IServiceScopeFactory _scopeFactory;
private readonly AccountService _accountService;
private readonly IConfiguration _configuration;

public LeaderboardService(IMemoryCache cache, Ss14ApiHelper apiHelper, IServiceScopeFactory factory, AccountService accountService)
public LeaderboardService(IMemoryCache cache, Ss14ApiHelper apiHelper, IServiceScopeFactory factory, AccountService accountService, IConfiguration configuration)
{
_cache = cache;
_apiHelper = apiHelper;
_scopeFactory = factory;
_accountService = accountService;
_configuration = configuration;
}

public Task StartAsync(CancellationToken cancellationToken)
Expand All @@ -50,7 +52,7 @@ private void DoWork(object? state)
foreach (var rangeOption in Enum.GetValues<RangeOption>())
{
var anonymousAuth = new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
GetLeaderboard(rangeOption, null, anonymousAuth, false).Wait();
GetLeaderboard(rangeOption, null, [], anonymousAuth, false).Wait();
}

sw.Stop();
Expand All @@ -68,8 +70,13 @@ public void Dispose()
_timer?.Dispose();
}

public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, string? username, AuthenticationState authenticationState, bool logAction = true)
public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, string? username, string[]? servers, AuthenticationState authenticationState, bool logAction = true)
{
if (servers == null || servers.Length == 0)
{
servers = _configuration.GetSection("ReplayUrls").Get<StorageUrl[]>()!.Select(x => x.FallBackServerName).ToArray();
}

var context = _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<ReplayDbContext>();

Account? accountCaller = null;
Expand Down Expand Up @@ -111,7 +118,10 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin
.Replace(" ", "-")
.Replace(".", "-")
.Replace("_", "-");
var cacheKey = "leaderboard-" + rangeOption + "-" + usernameCacheKey;

var serversCacheKey = string.Join("-", servers);

var cacheKey = "leaderboard-" + rangeOption + "-" + usernameCacheKey + "-" + serversCacheKey;
if (_cache.TryGetValue(cacheKey, out LeaderboardData? leaderboardData))
{
return leaderboardData!;
Expand All @@ -130,7 +140,6 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin
var stopwatch = new Stopwatch();
long stopwatchPrevious = 0;
stopwatch.Start();
var rangeTimespan = rangeOption.GetTimeSpan();
var leaderboards = new Dictionary<string, Leaderboard>()
{
{"MostSeenPlayers", new Leaderboard()
Expand Down Expand Up @@ -172,6 +181,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin
#region FUNNY SQL QUERIES

var mostplayed = await context.ReplayParticipants
.Where(p => servers.Contains(p.Replay.ServerName))
.Where(p => p.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.GroupBy(p => p.PlayerGuid)
.Select(pg => new {
Expand All @@ -195,6 +205,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin
stopwatch.Start();

var mostplayednoghost = await context.ReplayParticipants
.Where(p => servers.Contains(p.Replay.ServerName))
.Where(p => p.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.Where(p => p.Players!.Any(p => p.PlayerIcName != "Unknown"))
.GroupBy(p => p.PlayerGuid)
Expand All @@ -220,6 +231,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin
stopwatch.Start();

var mostantag = await context.ReplayParticipants
.Where(p => servers.Contains(p.Replay.ServerName))
.Where(p => p.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.Where(p => p.Players!.Any(p => p.AntagPrototypes.Count > 0))
.GroupBy(p => p.PlayerGuid)
Expand All @@ -246,6 +258,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin

var mostPlayedDepartments = await context.Players
.Where(p => p.EffectiveJobId != null)
.Where(p => servers.Contains(p.Participant.Replay.ServerName))
.Where(p => p.Participant.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.GroupBy(p => p.EffectiveJob!.Department)
.Select(pg => new {
Expand All @@ -272,6 +285,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin

var mostPlayedJobs = await context.Players
.Where(p => p.JobPrototypes.Count > 0)
.Where(p => servers.Contains(p.Participant.Replay.ServerName))
.Where(p => p.Participant.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.Select(p => p.JobPrototypes[0])
.GroupBy(p => p)
Expand Down Expand Up @@ -299,6 +313,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin

var perDepartmentPlayers = await context.Players
.Where(p => p.EffectiveJobId != null)
.Where(p => servers.Contains(p.Participant.Replay.ServerName))
.Where(p => p.Participant.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.GroupBy(p => new {
p.EffectiveJob!.Department,
Expand Down Expand Up @@ -335,6 +350,7 @@ public async Task<LeaderboardData> GetLeaderboard(RangeOption rangeOption, strin

var perJobPlayers = await context.Players
.Where(p => p.JobPrototypes.Count > 0)
.Where(p => servers.Contains(p.Participant.Replay.ServerName))
.Where(p => p.Participant.Replay!.Date >= (DateTime.UtcNow - rangeOption.GetNormalTimeSpan()))
.GroupBy(p => new {
Job = p.JobPrototypes[0],
Expand Down
Loading