Fix async chat actions and channel sync
This commit is contained in:
@@ -80,12 +80,13 @@ public sealed class MaxBridgeSyncService(
|
||||
var createdMessages = new List<(Chat Chat, Message Message)>();
|
||||
var updatedMessages = new List<(Chat Chat, Message Message)>();
|
||||
var previewNotificationMessages = new List<(Chat Chat, Message Message)>();
|
||||
var genericMediaHistoryRequests = new List<(string ExternalChatId, string? ChatUrl, DateTimeOffset PreviewAt)>();
|
||||
var genericMediaHistoryRequests = new List<(string ExternalChatId, string? ChatUrl, DateTimeOffset PreviewAt, bool IncrementUnread)>();
|
||||
var trackedChatsByExternalId = new Dictionary<string, Chat>(StringComparer.Ordinal);
|
||||
|
||||
foreach (var update in updates)
|
||||
{
|
||||
var nextWebUrl = CleanWebUrl(update.ChatUrl);
|
||||
var nextKind = ResolveChatKind(update.Kind);
|
||||
if (!trackedChatsByExternalId.TryGetValue(update.ExternalId, out var chat))
|
||||
{
|
||||
chat = await db.Chats
|
||||
@@ -95,6 +96,10 @@ public sealed class MaxBridgeSyncService(
|
||||
chat = await db.Chats
|
||||
.FirstOrDefaultAsync(x => x.WebUrl == nextWebUrl, cancellationToken);
|
||||
}
|
||||
if (chat is null)
|
||||
{
|
||||
chat = await FindDeletedChatTombstoneAsync(db, update, nextWebUrl, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (chat?.DeletedAt is not null)
|
||||
@@ -112,7 +117,7 @@ public sealed class MaxBridgeSyncService(
|
||||
Title = update.Title,
|
||||
AvatarUrl = update.AvatarUrl,
|
||||
WebUrl = nextWebUrl,
|
||||
Kind = ChatKind.MaxDialog
|
||||
Kind = nextKind ?? ChatKind.MaxDialog
|
||||
};
|
||||
db.Chats.Add(chat);
|
||||
changed++;
|
||||
@@ -149,6 +154,12 @@ public sealed class MaxBridgeSyncService(
|
||||
metadataChanged = true;
|
||||
}
|
||||
|
||||
if (nextKind is { } resolvedKind && chat.Kind != resolvedKind)
|
||||
{
|
||||
chat.Kind = resolvedKind;
|
||||
metadataChanged = true;
|
||||
}
|
||||
|
||||
if (metadataChanged)
|
||||
{
|
||||
chat.UpdatedAt = DateTimeOffset.UtcNow;
|
||||
@@ -189,7 +200,9 @@ public sealed class MaxBridgeSyncService(
|
||||
chat,
|
||||
chatWasCreated,
|
||||
incrementUnread,
|
||||
lastKnownMessage);
|
||||
lastKnownMessage,
|
||||
createPreviewMessages: chat.Kind != ChatKind.Channel,
|
||||
incrementGenericMediaUnread: chat.Kind == ChatKind.Channel);
|
||||
if (previewResult.Message is not null)
|
||||
{
|
||||
if (!await HasPreviewPlaceholderAsync(db, chat.Id, previewResult.Message, cancellationToken))
|
||||
@@ -203,12 +216,21 @@ public sealed class MaxBridgeSyncService(
|
||||
previewNotificationMessages.Add((chat, previewResult.NotificationMessage));
|
||||
}
|
||||
|
||||
var shouldFetchHistory = previewResult.ShouldFetchHistory ||
|
||||
(chat.Kind == ChatKind.Channel &&
|
||||
previewResult.PreviewAt is not null &&
|
||||
update.Messages.Count == 0 &&
|
||||
HasListClockTime(update.LastMessageTimeText));
|
||||
if (allowGenericMediaHistoryFetch &&
|
||||
previewResult.ShouldFetchHistory &&
|
||||
shouldFetchHistory &&
|
||||
previewResult.PreviewAt is { } previewAt &&
|
||||
!await HasMessageAtOrAfterAsync(db, chat.Id, previewAt, cancellationToken))
|
||||
{
|
||||
genericMediaHistoryRequests.Add((update.ExternalId, nextWebUrl ?? chat.WebUrl, previewAt));
|
||||
genericMediaHistoryRequests.Add((
|
||||
update.ExternalId,
|
||||
nextWebUrl ?? chat.WebUrl,
|
||||
previewAt,
|
||||
IncrementUnread: chat.Kind != ChatKind.Channel));
|
||||
}
|
||||
|
||||
if (previewResult.Changed)
|
||||
@@ -372,7 +394,7 @@ public sealed class MaxBridgeSyncService(
|
||||
{
|
||||
var dto = projection.ToDto(message);
|
||||
await hubContext.Clients.Group($"chat:{chat.Id}").SendAsync("MessageCreated", dto, cancellationToken);
|
||||
if (sendPushNotifications && message.Direction == MessageDirection.Incoming)
|
||||
if (sendPushNotifications && message.Direction == MessageDirection.Incoming && chat.Kind != ChatKind.Channel)
|
||||
{
|
||||
await pushNotifications.SendNewMessageAsync(chat, message, cancellationToken);
|
||||
}
|
||||
@@ -380,7 +402,7 @@ public sealed class MaxBridgeSyncService(
|
||||
|
||||
foreach (var (chat, message) in previewNotificationMessages)
|
||||
{
|
||||
if (sendPushNotifications && message.Direction == MessageDirection.Incoming)
|
||||
if (sendPushNotifications && message.Direction == MessageDirection.Incoming && chat.Kind != ChatKind.Channel)
|
||||
{
|
||||
await pushNotifications.SendNewMessageAsync(chat, message, cancellationToken);
|
||||
}
|
||||
@@ -413,7 +435,7 @@ public sealed class MaxBridgeSyncService(
|
||||
{
|
||||
changed += await ApplyUpdatesAsync(
|
||||
[history],
|
||||
incrementUnread,
|
||||
incrementUnread && request.IncrementUnread,
|
||||
sendPushNotifications,
|
||||
cancellationToken,
|
||||
allowGenericMediaHistoryFetch: false);
|
||||
@@ -433,7 +455,9 @@ public sealed class MaxBridgeSyncService(
|
||||
Chat chat,
|
||||
bool chatWasCreated,
|
||||
bool incrementUnread,
|
||||
LastKnownMessageSnapshot? lastKnownMessage)
|
||||
LastKnownMessageSnapshot? lastKnownMessage,
|
||||
bool createPreviewMessages,
|
||||
bool incrementGenericMediaUnread)
|
||||
{
|
||||
var preview = MessageTextSanitizer.CleanChatPreview(update.LastMessagePreview);
|
||||
if (string.IsNullOrWhiteSpace(preview))
|
||||
@@ -471,8 +495,7 @@ public sealed class MaxBridgeSyncService(
|
||||
chat.UpdatedAt = DateTimeOffset.UtcNow;
|
||||
|
||||
var echoesKnownOutgoing = IsKnownOutgoingPreviewEcho(lastKnownMessage, preview, previewAt);
|
||||
var shouldNotifyCandidate = !chatWasCreated &&
|
||||
!string.IsNullOrWhiteSpace(previousPreview) &&
|
||||
var shouldNotifyCandidate = (chatWasCreated || !string.IsNullOrWhiteSpace(previousPreview)) &&
|
||||
!echoesKnownOutgoing &&
|
||||
update.LastMessageIsOutgoing != true &&
|
||||
update.Messages.Count == 0 &&
|
||||
@@ -480,12 +503,12 @@ public sealed class MaxBridgeSyncService(
|
||||
var shouldNotify = shouldNotifyCandidate &&
|
||||
RememberPreviewNotification(chat.Id, preview, previewAt);
|
||||
|
||||
if (incrementUnread && shouldNotify && !isGenericMediaPreview)
|
||||
if (incrementUnread && shouldNotify && (!isGenericMediaPreview || incrementGenericMediaUnread))
|
||||
{
|
||||
chat.UnreadCount++;
|
||||
}
|
||||
|
||||
var message = shouldNotify && !isGenericMediaPreview
|
||||
var message = shouldNotify && !isGenericMediaPreview && createPreviewMessages
|
||||
? CreatePreviewMessage(chat, preview, previewAt)
|
||||
: null;
|
||||
return new ListPreviewApplyResult(true, message, null, shouldFetchHistory, previewAt);
|
||||
@@ -1298,6 +1321,49 @@ public sealed class MaxBridgeSyncService(
|
||||
return string.IsNullOrWhiteSpace(trimmed) ? null : trimmed;
|
||||
}
|
||||
|
||||
private static ChatKind? ResolveChatKind(string? value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Enum.TryParse<ChatKind>(value.Trim(), ignoreCase: true, out var parsed)
|
||||
? parsed
|
||||
: null;
|
||||
}
|
||||
|
||||
private static async Task<Chat?> FindDeletedChatTombstoneAsync(
|
||||
QMaxDbContext db,
|
||||
MaxChatUpdate update,
|
||||
string? nextWebUrl,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(update.Title))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var deletedChats = db.Chats
|
||||
.Where(x => x.DeletedAt != null && x.Title == update.Title);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(nextWebUrl))
|
||||
{
|
||||
return await deletedChats.FirstOrDefaultAsync(x => x.WebUrl == nextWebUrl, cancellationToken);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(update.AvatarUrl))
|
||||
{
|
||||
return await deletedChats.FirstOrDefaultAsync(x => x.AvatarUrl == update.AvatarUrl, cancellationToken);
|
||||
}
|
||||
|
||||
var titleMatches = await deletedChats
|
||||
.OrderByDescending(x => x.DeletedAt)
|
||||
.Take(2)
|
||||
.ToListAsync(cancellationToken);
|
||||
return titleMatches.Count == 1 ? titleMatches[0] : null;
|
||||
}
|
||||
|
||||
private static string? LastMessagePreview(string? text, IEnumerable<MessageAttachment> attachments)
|
||||
{
|
||||
var orderedAttachments = attachments.OrderBy(x => x.SortOrder).ToArray();
|
||||
|
||||
Reference in New Issue
Block a user