diff --git a/LightlessSyncServer/LightlessSyncServer/Hubs/LightlessHub.Chat.cs b/LightlessSyncServer/LightlessSyncServer/Hubs/LightlessHub.Chat.cs index 0b1f198..4b9d5bd 100644 --- a/LightlessSyncServer/LightlessSyncServer/Hubs/LightlessHub.Chat.cs +++ b/LightlessSyncServer/LightlessSyncServer/Hubs/LightlessHub.Chat.cs @@ -5,6 +5,7 @@ using System.Text.Json; using LightlessSync.API.Data.Enum; using LightlessSync.API.Dto.Chat; using LightlessSync.API.Dto.User; +using LightlessSyncServer.Models; using LightlessSyncServer.Services; using LightlessSyncServer.Utils; using LightlessSyncShared.Models; @@ -318,8 +319,8 @@ public partial class LightlessHub return; } - var requestedChannelKey = ChatChannelService.ChannelKey.FromDescriptor(channel); - var messageChannelKey = ChatChannelService.ChannelKey.FromDescriptor(messageEntry.Channel.WithNormalizedCustomKey()); + var requestedChannelKey = ChannelKey.FromDescriptor(channel); + var messageChannelKey = ChannelKey.FromDescriptor(messageEntry.Channel.WithNormalizedCustomKey()); if (!requestedChannelKey.Equals(messageChannelKey)) { await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "The reported message no longer matches this channel.").ConfigureAwait(false); @@ -433,7 +434,7 @@ public partial class LightlessHub await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Information, "Thank you. Your report has been queued for moderator review.").ConfigureAwait(false); } - private ChatSenderDescriptor BuildSenderDescriptor(ChatChannelDescriptor descriptor, ChatChannelService.ChatParticipantInfo participant, bool includeSensitiveInfo = false) + private ChatSenderDescriptor BuildSenderDescriptor(ChatChannelDescriptor descriptor, ChatParticipantInfo participant, bool includeSensitiveInfo = false) { var kind = descriptor.Type == ChatChannelType.Group ? ChatSenderKind.IdentifiedUser @@ -566,13 +567,4 @@ public partial class LightlessHub await Clients.Client(connectionId).Client_ReceiveServerMessage(MessageSeverity.Error, "Your chat access has been revoked.").ConfigureAwait(false); } } - - private readonly record struct ChatReportSnapshotItem( - string MessageId, - DateTime SentAtUtc, - string SenderUserUid, - string? SenderAlias, - bool SenderIsLightfinder, - string? SenderHashedCid, - string Message); -} \ No newline at end of file +} diff --git a/LightlessSyncServer/LightlessSyncServer/Models/BroadcastRedisEntry.cs b/LightlessSyncServer/LightlessSyncServer/Models/BroadcastRedisEntry.cs index b5fe478..1d39492 100644 --- a/LightlessSyncServer/LightlessSyncServer/Models/BroadcastRedisEntry.cs +++ b/LightlessSyncServer/LightlessSyncServer/Models/BroadcastRedisEntry.cs @@ -9,4 +9,4 @@ public class BroadcastRedisEntry() public bool OwnedBy(string userUid) => !string.IsNullOrEmpty(userUid) && string.Equals(OwnerUID, userUid, StringComparison.Ordinal); public bool HasOwner() => !string.IsNullOrEmpty(OwnerUID); -} \ No newline at end of file +} diff --git a/LightlessSyncServer/LightlessSyncServer/Models/ChatModels.cs b/LightlessSyncServer/LightlessSyncServer/Models/ChatModels.cs new file mode 100644 index 0000000..c85e385 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncServer/Models/ChatModels.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using LightlessSync.API.Data; +using LightlessSync.API.Dto.Chat; + +namespace LightlessSyncServer.Models; + +internal readonly record struct ChatReportSnapshotItem( + string MessageId, + DateTime SentAtUtc, + string SenderUserUid, + string? SenderAlias, + bool SenderIsLightfinder, + string? SenderHashedCid, + string Message); + +public readonly record struct ChatPresenceEntry( + ChatChannelDescriptor Channel, + ChannelKey ChannelKey, + string DisplayName, + ChatParticipantInfo Participant, + DateTime UpdatedAt); + +public readonly record struct ChatParticipantInfo( + string Token, + string UserUid, + UserData? User, + string? HashedCid, + bool IsLightfinder); + +public readonly record struct ChatMessageLogEntry( + string MessageId, + ChatChannelDescriptor Channel, + DateTime SentAtUtc, + string SenderToken, + string SenderUserUid, + UserData? SenderUser, + bool SenderIsLightfinder, + string? SenderHashedCid, + string Message); + +public readonly record struct ZoneChannelDefinition( + string Key, + string DisplayName, + ChatChannelDescriptor Descriptor, + IReadOnlyList TerritoryNames); + +public readonly record struct ChannelKey(ChatChannelType Type, ushort WorldId, string CustomKey) +{ + public static ChannelKey FromDescriptor(ChatChannelDescriptor descriptor) => + new( + descriptor.Type, + descriptor.Type == ChatChannelType.Zone ? descriptor.WorldId : (ushort)0, + NormalizeKey(descriptor.CustomKey)); + + private static string NormalizeKey(string? value) => + string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().ToUpperInvariant(); +} diff --git a/LightlessSyncServer/LightlessSyncServer/Models/ChatZoneDefinitions.cs b/LightlessSyncServer/LightlessSyncServer/Models/ChatZoneDefinitions.cs new file mode 100644 index 0000000..ebef986 --- /dev/null +++ b/LightlessSyncServer/LightlessSyncServer/Models/ChatZoneDefinitions.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using LightlessSync.API.Dto.Chat; + +namespace LightlessSyncServer.Models; + +internal static class ChatZoneDefinitions +{ + public static IReadOnlyList Defaults { get; } = + new[] + { + new ZoneChannelDefinition( + Key: "limsa", + DisplayName: "Limsa Lominsa", + Descriptor: new ChatChannelDescriptor + { + Type = ChatChannelType.Zone, + WorldId = 0, + ZoneId = 0, + CustomKey = "limsa" + }, + TerritoryNames: new[] + { + "Limsa Lominsa Lower Decks", + "Limsa Lominsa Upper Decks" + }), + new ZoneChannelDefinition( + Key: "gridania", + DisplayName: "Gridania", + Descriptor: new ChatChannelDescriptor + { + Type = ChatChannelType.Zone, + WorldId = 0, + ZoneId = 0, + CustomKey = "gridania" + }, + TerritoryNames: new[] + { + "New Gridania", + "Old Gridania" + }), + new ZoneChannelDefinition( + Key: "uldah", + DisplayName: "Ul'dah", + Descriptor: new ChatChannelDescriptor + { + Type = ChatChannelType.Zone, + WorldId = 0, + ZoneId = 0, + CustomKey = "uldah" + }, + TerritoryNames: new[] + { + "Ul'dah - Steps of Nald", + "Ul'dah - Steps of Thal" + }) + }; +} diff --git a/LightlessSyncServer/LightlessSyncServer/Services/ChatChannelService.cs b/LightlessSyncServer/LightlessSyncServer/Services/ChatChannelService.cs index 30a24b5..0a411d1 100644 --- a/LightlessSyncServer/LightlessSyncServer/Services/ChatChannelService.cs +++ b/LightlessSyncServer/LightlessSyncServer/Services/ChatChannelService.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using LightlessSync.API.Data; using LightlessSync.API.Dto.Chat; +using LightlessSyncServer.Models; using Microsoft.Extensions.Logging; namespace LightlessSyncServer.Services; @@ -11,7 +12,7 @@ namespace LightlessSyncServer.Services; public sealed class ChatChannelService { private readonly ILogger _logger; - private readonly Dictionary _zoneDefinitions = new(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary _zoneDefinitions; private readonly Dictionary> _membersByChannel = new(); private readonly Dictionary> _presenceByUser = new(StringComparer.Ordinal); private readonly Dictionary> _participantsByChannel = new(); @@ -23,54 +24,8 @@ public sealed class ChatChannelService public ChatChannelService(ILogger logger) { _logger = logger; - - AddZoneDefinition(new ZoneChannelDefinition( - Key: "limsa", - DisplayName: "Limsa Lominsa", - Descriptor: new ChatChannelDescriptor - { - Type = ChatChannelType.Zone, - WorldId = 0, - ZoneId = 0, - CustomKey = "limsa" - }, - TerritoryNames: new[] - { - "Limsa Lominsa Lower Decks", - "Limsa Lominsa Upper Decks" - })); - - AddZoneDefinition(new ZoneChannelDefinition( - Key: "gridania", - DisplayName: "Gridania", - Descriptor: new ChatChannelDescriptor - { - Type = ChatChannelType.Zone, - WorldId = 0, - ZoneId = 0, - CustomKey = "gridania" - }, - TerritoryNames: new[] - { - "New Gridania", - "Old Gridania" - })); - - AddZoneDefinition(new ZoneChannelDefinition( - Key: "uldah", - DisplayName: "Ul'dah", - Descriptor: new ChatChannelDescriptor - { - Type = ChatChannelType.Zone, - WorldId = 0, - ZoneId = 0, - CustomKey = "uldah" - }, - TerritoryNames: new[] - { - "Ul'dah - Steps of Nald", - "Ul'dah - Steps of Thal" - })); + _zoneDefinitions = ChatZoneDefinitions.Defaults + .ToDictionary(definition => definition.Key, StringComparer.OrdinalIgnoreCase); } public IReadOnlyList GetZoneChannelInfos() => @@ -454,11 +409,6 @@ public sealed class ChatChannelService return true; } - private void AddZoneDefinition(ZoneChannelDefinition definition) - { - _zoneDefinitions[definition.Key] = definition; - } - private static string GenerateToken() { Span buffer = stackalloc byte[8]; @@ -468,47 +418,4 @@ public sealed class ChatChannelService private static string Describe(ChannelKey key) => $"{key.Type}:{key.WorldId}:{key.CustomKey}"; - - private static string NormalizeKey(string? value) - => string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().ToUpperInvariant(); - - public readonly record struct ChatPresenceEntry( - ChatChannelDescriptor Channel, - ChannelKey ChannelKey, - string DisplayName, - ChatParticipantInfo Participant, - DateTime UpdatedAt); - - public readonly record struct ChatParticipantInfo( - string Token, - string UserUid, - UserData? User, - string? HashedCid, - bool IsLightfinder); - - public readonly record struct ChatMessageLogEntry( - string MessageId, - ChatChannelDescriptor Channel, - DateTime SentAtUtc, - string SenderToken, - string SenderUserUid, - UserData? SenderUser, - bool SenderIsLightfinder, - string? SenderHashedCid, - string Message); - - public readonly record struct ZoneChannelDefinition( - string Key, - string DisplayName, - ChatChannelDescriptor Descriptor, - IReadOnlyList TerritoryNames); - - public readonly record struct ChannelKey(ChatChannelType Type, ushort WorldId, string CustomKey) - { - public static ChannelKey FromDescriptor(ChatChannelDescriptor descriptor) - => new( - descriptor.Type, - descriptor.Type == ChatChannelType.Zone ? descriptor.WorldId : (ushort)0, - NormalizeKey(descriptor.CustomKey)); - } }