Skip to content
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
33 changes: 24 additions & 9 deletions Application/ApplicationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,17 @@ public IList<Server> GetServers()
.ToList();
}

public IList<IManagerCommand> GetCommands()
public IReadOnlyList<IManagerCommand> Commands
{
return _commands;
get
{
lock (_commands)
{
return _commands.ToImmutableList();
}
}
}

public IReadOnlyList<IManagerCommand> Commands => _commands.ToImmutableList();

private Task UpdateServerStates()
{
var index = 0;
Expand Down Expand Up @@ -557,21 +561,25 @@ await scriptPlugin.Initialize(this, _scriptCommandFactory, _scriptPluginServiceR
#region COMMANDS
if (await ClientSvc.HasOwnerAsync(_isRunningTokenSource.Token))
{
_commands.RemoveAll(_cmd => _cmd.GetType() == typeof(OwnerCommand));
lock (_commands)
{
_commands.RemoveAll(cmd => cmd.GetType() == typeof(OwnerCommand));
}
}

List<IManagerCommand> commandsToAddToConfig = new List<IManagerCommand>();
List<IManagerCommand> commandsToAddToConfig = [];
var cmdConfig = _commandConfiguration.Configuration();

if (cmdConfig == null)
{
cmdConfig = new CommandConfiguration();
commandsToAddToConfig.AddRange(_commands);
commandsToAddToConfig.AddRange(Commands);
}

else
{
var unsavedCommands = _commands.Where(_cmd => !cmdConfig.Commands.Keys.Contains(_cmd.CommandConfigNameForType()));
var unsavedCommands = Commands
.Where(cmd => !cmdConfig.Commands.ContainsKey(cmd.CommandConfigNameForType()));
commandsToAddToConfig.AddRange(unsavedCommands);
}

Expand Down Expand Up @@ -842,7 +850,14 @@ public void AddAdditionalCommand(IManagerCommand command)
}
}

public void RemoveCommandByName(string commandName) => _commands.RemoveAll(_command => _command.Name == commandName);
public void RemoveCommandByName(string commandName)
{
lock (_commands)
{
_commands.RemoveAll(command => command.Name == commandName);
}
}

public IAlertManager AlertManager => _alertManager;

public async Task<Server> AddServerAsync(ServerConfiguration config, bool persistConfig = true, CancellationToken token = default)
Expand Down
5 changes: 4 additions & 1 deletion Application/CoreEventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,10 @@ private async Task BuildLegacyEventTask(IManager manager, CoreEvent coreEvent, G
{
if (manager.IsRunning || OverrideEvents.Contains(gameEvent.Type))
{
await manager.ExecuteEvent(gameEvent);
using var timeoutToken = new CancellationTokenSource(Utilities.DefaultCommandTimeout);
using var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(manager.CancellationToken, timeoutToken.Token);

await manager.ExecuteEvent(gameEvent).WaitAsync(linkedToken.Token);
await IGameEventSubscriptions.InvokeEventAsync(coreEvent, manager.CancellationToken);
return;
}
Expand Down
1 change: 1 addition & 0 deletions Application/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ private static void ConfigureServices(IServiceCollection serviceCollection)
.AddSingleton<IMetaServiceV2, MetaServiceV2>()
.AddSingleton<ClientService>()
.AddSingleton<PenaltyService>()
.AddSingleton<IAnnouncementService, AnnouncementService>()
.AddSingleton<ChangeHistoryService>()
.AddSingleton<IMetaRegistration, MetaRegistration>()
.AddSingleton<IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
Expand Down
3 changes: 2 additions & 1 deletion Application/Meta/AdministeredPenaltyResourceQueryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public async Task<ResourceQueryHelperResult<AdministeredPenaltyResponse>> QueryR
When = _penalty.When,
ExpirationDate = _penalty.Expires,
IsLinked = _penalty.OffenderId != query.ClientId,
IsSensitive = _penalty.Type == EFPenalty.PenaltyType.Flag
IsSensitive = _penalty.Type == EFPenalty.PenaltyType.Flag,
Type = MetaType.Penalized
})
.ToListAsync();

Expand Down
12 changes: 7 additions & 5 deletions Application/Meta/MetaRegistration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Humanizer;
using Microsoft.Extensions.Logging;
using Stats.Dtos;
using WebfrontCore.Core.Auth;
using ILogger = Microsoft.Extensions.Logging.ILogger;

namespace IW4MAdmin.Application.Meta
Expand All @@ -34,16 +35,17 @@ public void Register()
metaService.AddRuntimeMeta<ClientPaginationRequest, InformationResponse>(MetaType.Information,
GetProfileMeta);
metaService.AddRuntimeMeta<ClientPaginationRequest, ReceivedPenaltyResponse>(MetaType.ReceivedPenalty,
GetReceivedPenaltiesMeta);
GetReceivedPenaltiesMeta, nameof(WebfrontEntity.Penalty));
metaService.AddRuntimeMeta<ClientPaginationRequest, AdministeredPenaltyResponse>(MetaType.Penalized,
GetAdministeredPenaltiesMeta);
GetAdministeredPenaltiesMeta, nameof(WebfrontEntity.Penalty));
metaService.AddRuntimeMeta<ClientPaginationRequest, UpdatedAliasResponse>(MetaType.AliasUpdate,
GetUpdatedAliasMeta);
GetUpdatedAliasMeta, nameof(WebfrontEntity.MetaAliasUpdate));
metaService.AddRuntimeMeta<ClientPaginationRequest, ConnectionHistoryResponse>(MetaType.ConnectionHistory,
GetConnectionHistoryMeta);
metaService.AddRuntimeMeta<ClientPaginationRequest, PermissionLevelChangedResponse>(
MetaType.PermissionLevel, GetPermissionLevelMeta);
metaService.AddRuntimeMeta<ClientPaginationRequest, MessageResponse>(MetaType.ChatMessage, GetChatMessages);
MetaType.PermissionLevel, GetPermissionLevelMeta, nameof(WebfrontEntity.ClientLevel));
metaService.AddRuntimeMeta<ClientPaginationRequest, MessageResponse>(MetaType.ChatMessage, GetChatMessages,
nameof(WebfrontEntity.ChatMessage));
}

private async Task<IEnumerable<InformationResponse>> GetProfileMeta(ClientPaginationRequest request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ on change.OriginEntityId equals client.ClientId
CurrentPermissionLevelValue = change.CurrentValue,
When = change.TimeChanged,
ClientId = change.TargetEntityId,
Type = MetaType.PermissionLevel,
IsSensitive = true
};

Expand Down
73 changes: 53 additions & 20 deletions Application/Misc/MetaServiceV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,36 @@
using Data.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SharedLibraryCore;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Dtos;
using SharedLibraryCore.Interfaces;
using SharedLibraryCore.QueryHelper;
using WebfrontCore.Core.Auth;
using ILogger = Microsoft.Extensions.Logging.ILogger;

namespace IW4MAdmin.Application.Misc;

public class MetaServiceV2 : IMetaServiceV2
{
private readonly IDictionary<MetaType, List<dynamic>> _metaActions;
protected class MetaRegistration
{
public required dynamic Action;
public required WebfrontEntity EntityType;
}

private readonly IDictionary<MetaType, List<MetaRegistration>> _metaActions;
private readonly IDatabaseContextFactory _contextFactory;
private readonly ApplicationConfiguration _configuration;
private readonly ILogger _logger;

public MetaServiceV2(ILogger<MetaServiceV2> logger, IDatabaseContextFactory contextFactory, IServiceProvider serviceProvider)
public MetaServiceV2(ILogger<MetaServiceV2> logger, IDatabaseContextFactory contextFactory,
ApplicationConfiguration configuration)
{
_logger = logger;
_metaActions = new Dictionary<MetaType, List<dynamic>>();
_metaActions = new Dictionary<MetaType, List<MetaRegistration>>();
_contextFactory = contextFactory;
_configuration = configuration;
}

public async Task SetPersistentMeta(string metaKey, string metaValue, int clientId,
Expand Down Expand Up @@ -184,7 +196,7 @@ public async Task<T> GetPersistentMetaValue<T>(string metaKey, int clientId, Can

if (meta is null)
{
return default;
return null;
}

try
Expand All @@ -194,7 +206,7 @@ public async Task<T> GetPersistentMetaValue<T>(string metaKey, int clientId, Can
catch (Exception ex)
{
_logger.LogError(ex, "Could not deserialize meta with key {Key} and value {Value}", metaKey, meta.Value);
return default;
return null;
}
}

Expand All @@ -208,7 +220,7 @@ public async Task<EFMeta> GetPersistentMetaByLookup(string metaKey, string looku
if (metaValue is null)
{
_logger.LogDebug("No meta exists for key {Key}, clientId {ClientId}", metaKey, clientId);
return default;
return null;
}

var lookupMeta = await context.EFMeta.FirstOrDefaultAsync(meta => meta.Key == lookupKey, token);
Expand All @@ -217,15 +229,15 @@ public async Task<EFMeta> GetPersistentMetaByLookup(string metaKey, string looku
{
_logger.LogWarning("No lookup meta exists for metaKey {MetaKey} and lookupKey {LookupKey}", metaKey,
lookupKey);
return default;
return null;
}

var lookupId = int.Parse(metaValue.Value);
var lookupValues = JsonSerializer.Deserialize<List<LookupValue<string>>>(lookupMeta.Value);

if (lookupValues is null)
{
return default;
return null;
}

var foundLookup = lookupValues.FirstOrDefault(value => value.Id == lookupId);
Expand All @@ -244,7 +256,7 @@ public async Task<EFMeta> GetPersistentMetaByLookup(string metaKey, string looku

_logger.LogWarning("No lookup meta found for provided lookup id {MetaKey}, {LookupKey}, {LookupId}",
metaKey, lookupKey, lookupId);
return default;
return null;
}

public async Task RemovePersistentMeta(string metaKey, int clientId, CancellationToken token = default)
Expand Down Expand Up @@ -357,14 +369,14 @@ public async Task<T> GetPersistentMetaValue<T>(string metaKey, CancellationToken
{
if (string.IsNullOrWhiteSpace(metaKey))
{
return default;
return null;
}

var meta = await GetPersistentMeta(metaKey, token);

if (meta is null)
{
return default;
return null;
}

try
Expand All @@ -374,7 +386,7 @@ public async Task<T> GetPersistentMetaValue<T>(string metaKey, CancellationToken
catch (Exception ex)
{
_logger.LogError(ex, "Could not serialize meta with key {Key} and value {Value}", metaKey, meta.Value);
return default;
return null;
}
}

Expand All @@ -401,24 +413,37 @@ public async Task RemovePersistentMeta(string metaKey, CancellationToken token =
}

public void AddRuntimeMeta<T, TReturnType>(MetaType metaKey,
Func<T, CancellationToken, Task<IEnumerable<TReturnType>>> metaAction)
Func<T, CancellationToken, Task<IEnumerable<TReturnType>>> metaAction, string entityPermission)
where T : PaginationRequest where TReturnType : IClientMeta
{
if (!_metaActions.ContainsKey(metaKey))
var entity = Enum.Parse<WebfrontEntity>(entityPermission);
if (!_metaActions.TryGetValue(metaKey, out var action))
{
_metaActions.Add(metaKey, new List<dynamic> { metaAction });
_metaActions.Add(metaKey, [new MetaRegistration { Action = metaAction, EntityType = entity }]);
}

else
{
_metaActions[metaKey].Add(metaAction);
action.Add(new MetaRegistration { Action = metaAction, EntityType = entity });
}
}

public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request, CancellationToken token = default)
public void AddRuntimeMeta<T, TReturnType>(MetaType metaKey,
Func<T, CancellationToken, Task<IEnumerable<TReturnType>>> metaAction)
where T : PaginationRequest where TReturnType : IClientMeta
{
AddRuntimeMeta(metaKey, metaAction, nameof(WebfrontEntity.Default));
}

public async Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request,
CancellationToken token = default)
{
var metas = await Task.WhenAll(_metaActions.Where(kvp => kvp.Key != MetaType.Information)
.Select(async kvp => await kvp.Value[0](request, token)));
.SelectMany(kvp => kvp.Value)
.Where(reg => reg.EntityType == WebfrontEntity.Default || _configuration.HasPermission(
request.RequestPermission,
reg.EntityType, WebfrontPermission.Read))
.Select(async reg => await reg.Action(request, token)));

return metas.SelectMany(m => (IEnumerable<IClientMeta>)m)
.OrderByDescending(m => m.When)
Expand All @@ -434,14 +459,22 @@ public async Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest requ
var allMeta = new List<T>();

var completedMeta = await Task.WhenAll(_metaActions[metaType].Select(async individualMetaRegistration =>
(IEnumerable<T>)await individualMetaRegistration(request, token)));
(IEnumerable<T>)await individualMetaRegistration.Action(request, token)));

allMeta.AddRange(completedMeta.SelectMany(meta => meta));

return ProcessInformationMeta(allMeta);
}

var meta = await _metaActions[metaType][0](request, token) as IEnumerable<T>;
var registration = _metaActions[metaType][0];

if (registration.EntityType != WebfrontEntity.Default && !_configuration.HasPermission(request.RequestPermission,
registration.EntityType, WebfrontPermission.Read))
{
return [];
}

var meta = await registration.Action(request, token) as IEnumerable<T>;

return meta;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public void RegisterCommands(CsPluginInstance instance, Assembly assembly)
/// </summary>
private void RemoveConflictingCommands(Command newCommand, string fileName)
{
var conflicts = manager.GetCommands()
var conflicts = manager.Commands
.Where(existing => IsConflict((Command)existing, newCommand))
.ToList();

Expand Down
3 changes: 2 additions & 1 deletion Application/QueryHelpers/ChatResourceQueryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ public async Task<ResourceQueryHelperResult<MessageResponse>> QueryResource(Chat
? Server.Game.IW4
: (Server.Game)message.Server.GameName.Value,
SentIngame = message.SentIngame,
IsHidden = message.Server.IsPasswordProtected
IsHidden = message.Server.IsPasswordProtected,
Type = MetaType.ChatMessage
});

iqResponse = query.Direction == SharedLibraryCore.Dtos.SortDirection.Descending
Expand Down
12 changes: 12 additions & 0 deletions Data/Context/DatabaseContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public abstract class DatabaseContext : DbContext
#region MISC

public DbSet<EFInboxMessage> InboxMessages { get; set; }
public DbSet<EFAnnouncement> Announcements { get; set; }
public DbSet<EFServerSnapshot> ServerSnapshots { get;set; }
public DbSet<EFClientConnectionHistory> ConnectionHistory { get; set; }

Expand Down Expand Up @@ -155,6 +156,17 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)

modelBuilder.Entity<EFServerSnapshot>(ent => ent.HasIndex(snapshot => snapshot.CapturedAt));

modelBuilder.Entity<EFAnnouncement>(ent =>
{
ent.HasIndex(a => a.IsActive);
ent.HasIndex(a => a.IsGlobalNotice);
ent.HasOne(a => a.CreatedByClient)
.WithMany()
.HasForeignKey(a => a.CreatedByClientId)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<EFAnnouncement>().ToTable(nameof(EFAnnouncement));

// force full name for database conversion
modelBuilder.Entity<EFClient>().ToTable("EFClients");
modelBuilder.Entity<EFAlias>().ToTable("EFAlias");
Expand Down
Loading
Loading