1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-05 21:23:22 +08:00

Fix handling of local echo deduplication

This commit is contained in:
Dan Balasescu 2022-11-04 16:42:59 +09:00
parent 4f8e912f06
commit 58396d49dc
6 changed files with 51 additions and 23 deletions

View File

@ -28,6 +28,7 @@ namespace osu.Game.Online.API.Requests
req.AddParameter(@"target_id", user.Id.ToString()); req.AddParameter(@"target_id", user.Id.ToString());
req.AddParameter(@"message", message.Content); req.AddParameter(@"message", message.Content);
req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant()); req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant());
req.AddParameter(@"uuid", message.Uuid);
return req; return req;
} }

View File

@ -25,6 +25,7 @@ namespace osu.Game.Online.API.Requests
req.Method = HttpMethod.Post; req.Method = HttpMethod.Post;
req.AddParameter(@"is_action", Message.IsAction.ToString().ToLowerInvariant()); req.AddParameter(@"is_action", Message.IsAction.ToString().ToLowerInvariant());
req.AddParameter(@"message", Message.Content); req.AddParameter(@"message", Message.Content);
req.AddParameter(@"uuid", Message.Uuid);
return req; return req;
} }

View File

@ -134,6 +134,14 @@ namespace osu.Game.Online.Chat
/// <param name="messages"></param> /// <param name="messages"></param>
public void AddNewMessages(params Message[] messages) public void AddNewMessages(params Message[] messages)
{ {
foreach (var m in messages)
{
LocalEchoMessage localEcho = pendingMessages.FirstOrDefault(local => local.Uuid == m.Uuid);
if (localEcho != null)
ReplaceMessage(localEcho, m);
}
messages = messages.Except(Messages).ToArray(); messages = messages.Except(Messages).ToArray();
if (messages.Length == 0) return; if (messages.Length == 0) return;

View File

@ -85,8 +85,21 @@ namespace osu.Game.Online.Chat
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
connector.ChannelJoined += ch => Schedule(() => joinChannel(ch)); connector.ChannelJoined += ch => Schedule(() =>
{
var localChannel = getChannel(ch);
if (localChannel != ch)
{
localChannel.Joined.Value = true;
localChannel.Id = ch.Id;
}
joinChannel(localChannel);
});
connector.NewMessages += msgs => Schedule(() => addMessages(msgs)); connector.NewMessages += msgs => Schedule(() => addMessages(msgs));
connector.PresenceReceived += () => Schedule(() => connector.PresenceReceived += () => Schedule(() =>
{ {
if (!channelsInitialised) if (!channelsInitialised)
@ -189,7 +202,8 @@ namespace osu.Game.Online.Chat
Timestamp = DateTimeOffset.Now, Timestamp = DateTimeOffset.Now,
ChannelId = target.Id, ChannelId = target.Id,
IsAction = isAction, IsAction = isAction,
Content = text Content = text,
Uuid = Guid.NewGuid().ToString()
}; };
target.AddLocalEcho(message); target.AddLocalEcho(message);
@ -199,13 +213,7 @@ namespace osu.Game.Online.Chat
{ {
var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(target.Users.First(), message); var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(target.Users.First(), message);
createNewPrivateMessageRequest.Success += createRes => createNewPrivateMessageRequest.Success += _ => dequeueAndRun();
{
target.Id = createRes.ChannelID;
target.ReplaceMessage(message, createRes.Message);
dequeueAndRun();
};
createNewPrivateMessageRequest.Failure += exception => createNewPrivateMessageRequest.Failure += exception =>
{ {
handlePostException(exception); handlePostException(exception);
@ -219,12 +227,7 @@ namespace osu.Game.Online.Chat
var req = new PostMessageRequest(message); var req = new PostMessageRequest(message);
req.Success += m => req.Success += m => dequeueAndRun();
{
target.ReplaceMessage(message, m);
dequeueAndRun();
};
req.Failure += exception => req.Failure += exception =>
{ {
handlePostException(exception); handlePostException(exception);
@ -403,7 +406,20 @@ namespace osu.Game.Online.Chat
{ {
Channel found = null; Channel found = null;
bool lookupCondition(Channel ch) => lookup.Id > 0 ? ch.Id == lookup.Id : lookup.Name == ch.Name; bool lookupCondition(Channel ch)
{
// If both channels have an id, use that.
if (lookup.Id > 0 && ch.Id > 0)
return ch.Id == lookup.Id;
// In the case that the local echo is received in a new channel (i.e. one that does not yet have an ID),
// then we need to check for any existing channel with the message containing the same message matched by UUID.
if (lookup.Messages.Count > 0 && ch.Messages.Any(m => m.Uuid == lookup.Messages.Last().Uuid))
return true;
// As a last resort, fallback to matching by name.
return lookup.Name == ch.Name;
}
var available = AvailableChannels.FirstOrDefault(lookupCondition); var available = AvailableChannels.FirstOrDefault(lookupCondition);
if (available != null) if (available != null)

View File

@ -37,6 +37,12 @@ namespace osu.Game.Online.Chat
set => Sender = new APIUser { Id = value }; set => Sender = new APIUser { Id = value };
} }
/// <summary>
/// A unique identifier for this message. Sent to and from osu!web to use for deduplication.
/// </summary>
[JsonProperty(@"uuid")]
public string Uuid { get; set; } = string.Empty;
[JsonConstructor] [JsonConstructor]
public Message() public Message()
{ {

View File

@ -2,9 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
@ -126,12 +124,10 @@ namespace osu.Game.Online.Notifications.WebSocket
NewChatMessageData? messageData = JsonConvert.DeserializeObject<NewChatMessageData>(message.Data.ToString()); NewChatMessageData? messageData = JsonConvert.DeserializeObject<NewChatMessageData>(message.Data.ToString());
Debug.Assert(messageData != null); Debug.Assert(messageData != null);
List<Message> messages = messageData.Messages.Where(m => m.Sender.OnlineID != api.LocalUser.Value.OnlineID).ToList(); foreach (var msg in messageData.Messages)
HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId, Messages = { msg } });
foreach (var msg in messages) HandleMessages(messageData.Messages);
HandleJoinedChannel(new Channel(msg.Sender) { Id = msg.ChannelId });
HandleMessages(messages);
break; break;
} }