clean up structs and seperate zone definitions
This commit is contained in:
@@ -5,6 +5,7 @@ using System.Text.Json;
|
|||||||
using LightlessSync.API.Data.Enum;
|
using LightlessSync.API.Data.Enum;
|
||||||
using LightlessSync.API.Dto.Chat;
|
using LightlessSync.API.Dto.Chat;
|
||||||
using LightlessSync.API.Dto.User;
|
using LightlessSync.API.Dto.User;
|
||||||
|
using LightlessSyncServer.Models;
|
||||||
using LightlessSyncServer.Services;
|
using LightlessSyncServer.Services;
|
||||||
using LightlessSyncServer.Utils;
|
using LightlessSyncServer.Utils;
|
||||||
using LightlessSyncShared.Models;
|
using LightlessSyncShared.Models;
|
||||||
@@ -318,8 +319,8 @@ public partial class LightlessHub
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestedChannelKey = ChatChannelService.ChannelKey.FromDescriptor(channel);
|
var requestedChannelKey = ChannelKey.FromDescriptor(channel);
|
||||||
var messageChannelKey = ChatChannelService.ChannelKey.FromDescriptor(messageEntry.Channel.WithNormalizedCustomKey());
|
var messageChannelKey = ChannelKey.FromDescriptor(messageEntry.Channel.WithNormalizedCustomKey());
|
||||||
if (!requestedChannelKey.Equals(messageChannelKey))
|
if (!requestedChannelKey.Equals(messageChannelKey))
|
||||||
{
|
{
|
||||||
await Clients.Caller.Client_ReceiveServerMessage(MessageSeverity.Error, "The reported message no longer matches this channel.").ConfigureAwait(false);
|
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);
|
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
|
var kind = descriptor.Type == ChatChannelType.Group
|
||||||
? ChatSenderKind.IdentifiedUser
|
? 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);
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,4 +9,4 @@ public class BroadcastRedisEntry()
|
|||||||
public bool OwnedBy(string userUid) => !string.IsNullOrEmpty(userUid) && string.Equals(OwnerUID, userUid, StringComparison.Ordinal);
|
public bool OwnedBy(string userUid) => !string.IsNullOrEmpty(userUid) && string.Equals(OwnerUID, userUid, StringComparison.Ordinal);
|
||||||
|
|
||||||
public bool HasOwner() => !string.IsNullOrEmpty(OwnerUID);
|
public bool HasOwner() => !string.IsNullOrEmpty(OwnerUID);
|
||||||
}
|
}
|
||||||
|
|||||||
58
LightlessSyncServer/LightlessSyncServer/Models/ChatModels.cs
Normal file
58
LightlessSyncServer/LightlessSyncServer/Models/ChatModels.cs
Normal file
@@ -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<string> 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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using LightlessSync.API.Dto.Chat;
|
||||||
|
|
||||||
|
namespace LightlessSyncServer.Models;
|
||||||
|
|
||||||
|
internal static class ChatZoneDefinitions
|
||||||
|
{
|
||||||
|
public static IReadOnlyList<ZoneChannelDefinition> 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"
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using LightlessSync.API.Data;
|
using LightlessSync.API.Data;
|
||||||
using LightlessSync.API.Dto.Chat;
|
using LightlessSync.API.Dto.Chat;
|
||||||
|
using LightlessSyncServer.Models;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace LightlessSyncServer.Services;
|
namespace LightlessSyncServer.Services;
|
||||||
@@ -11,7 +12,7 @@ namespace LightlessSyncServer.Services;
|
|||||||
public sealed class ChatChannelService
|
public sealed class ChatChannelService
|
||||||
{
|
{
|
||||||
private readonly ILogger<ChatChannelService> _logger;
|
private readonly ILogger<ChatChannelService> _logger;
|
||||||
private readonly Dictionary<string, ZoneChannelDefinition> _zoneDefinitions = new(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, ZoneChannelDefinition> _zoneDefinitions;
|
||||||
private readonly Dictionary<ChannelKey, HashSet<string>> _membersByChannel = new();
|
private readonly Dictionary<ChannelKey, HashSet<string>> _membersByChannel = new();
|
||||||
private readonly Dictionary<string, Dictionary<ChannelKey, ChatPresenceEntry>> _presenceByUser = new(StringComparer.Ordinal);
|
private readonly Dictionary<string, Dictionary<ChannelKey, ChatPresenceEntry>> _presenceByUser = new(StringComparer.Ordinal);
|
||||||
private readonly Dictionary<ChannelKey, Dictionary<string, ChatParticipantInfo>> _participantsByChannel = new();
|
private readonly Dictionary<ChannelKey, Dictionary<string, ChatParticipantInfo>> _participantsByChannel = new();
|
||||||
@@ -23,54 +24,8 @@ public sealed class ChatChannelService
|
|||||||
public ChatChannelService(ILogger<ChatChannelService> logger)
|
public ChatChannelService(ILogger<ChatChannelService> logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_zoneDefinitions = ChatZoneDefinitions.Defaults
|
||||||
AddZoneDefinition(new ZoneChannelDefinition(
|
.ToDictionary(definition => definition.Key, StringComparer.OrdinalIgnoreCase);
|
||||||
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"
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<ZoneChatChannelInfoDto> GetZoneChannelInfos() =>
|
public IReadOnlyList<ZoneChatChannelInfoDto> GetZoneChannelInfos() =>
|
||||||
@@ -454,11 +409,6 @@ public sealed class ChatChannelService
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddZoneDefinition(ZoneChannelDefinition definition)
|
|
||||||
{
|
|
||||||
_zoneDefinitions[definition.Key] = definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateToken()
|
private static string GenerateToken()
|
||||||
{
|
{
|
||||||
Span<byte> buffer = stackalloc byte[8];
|
Span<byte> buffer = stackalloc byte[8];
|
||||||
@@ -468,47 +418,4 @@ public sealed class ChatChannelService
|
|||||||
|
|
||||||
private static string Describe(ChannelKey key)
|
private static string Describe(ChannelKey key)
|
||||||
=> $"{key.Type}:{key.WorldId}:{key.CustomKey}";
|
=> $"{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<string> 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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user