mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:37:28 +08:00
Merge pull request #21073 from smoogipoo/chat-silences
Remove chat messages from silenced users
This commit is contained in:
commit
f7913cbf1c
@ -23,6 +23,7 @@ namespace osu.Game.Tests.Chat
|
||||
private ChannelManager channelManager;
|
||||
private int currentMessageId;
|
||||
private List<Message> sentMessages;
|
||||
private List<int> silencedUserIds;
|
||||
|
||||
[SetUp]
|
||||
public void Setup() => Schedule(() =>
|
||||
@ -39,6 +40,7 @@ namespace osu.Game.Tests.Chat
|
||||
{
|
||||
currentMessageId = 0;
|
||||
sentMessages = new List<Message>();
|
||||
silencedUserIds = new List<int>();
|
||||
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
@ -56,6 +58,11 @@ namespace osu.Game.Tests.Chat
|
||||
handleMarkChannelAsReadRequest(markRead);
|
||||
return true;
|
||||
|
||||
case ChatAckRequest ack:
|
||||
ack.TriggerSuccess(new ChatAckResponse { Silences = silencedUserIds.Select(u => new ChatSilence { UserId = u }).ToList() });
|
||||
silencedUserIds.Clear();
|
||||
return true;
|
||||
|
||||
case GetUpdatesRequest updatesRequest:
|
||||
updatesRequest.TriggerSuccess(new GetUpdatesResponse
|
||||
{
|
||||
@ -115,6 +122,28 @@ namespace osu.Game.Tests.Chat
|
||||
AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSilencedUsersAreRemoved()
|
||||
{
|
||||
Channel channel = null;
|
||||
|
||||
AddStep("join channel and select it", () =>
|
||||
{
|
||||
channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public));
|
||||
channelManager.CurrentChannel.Value = channel;
|
||||
});
|
||||
|
||||
AddStep("post message", () => channelManager.PostMessage("Definitely something bad"));
|
||||
|
||||
AddStep("mark user as silenced and send ack request", () =>
|
||||
{
|
||||
silencedUserIds.Add(API.LocalUser.Value.OnlineID);
|
||||
channelManager.SendAck();
|
||||
});
|
||||
|
||||
AddAssert("channel has no more messages", () => channel.Messages, () => Is.Empty);
|
||||
}
|
||||
|
||||
private void handlePostMessageRequest(PostMessageRequest request)
|
||||
{
|
||||
var message = new Message(++currentMessageId)
|
||||
|
@ -40,8 +40,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
private ChannelManager channelManager;
|
||||
|
||||
private readonly APIUser testUser = new APIUser { Username = "test user", Id = 5071479 };
|
||||
private readonly APIUser testUser1 = new APIUser { Username = "test user", Id = 5071480 };
|
||||
|
||||
private Channel[] testChannels;
|
||||
private Message[] initialMessages;
|
||||
|
||||
private Channel testChannel1 => testChannels[0];
|
||||
private Channel testChannel2 => testChannels[1];
|
||||
@ -49,10 +51,14 @@ namespace osu.Game.Tests.Visual.Online
|
||||
[Resolved]
|
||||
private OsuConfigManager config { get; set; } = null!;
|
||||
|
||||
private int currentMessageId;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
currentMessageId = 0;
|
||||
testChannels = Enumerable.Range(1, 10).Select(createPublicChannel).ToArray();
|
||||
initialMessages = testChannels.SelectMany(createChannelMessages).ToArray();
|
||||
|
||||
Child = new DependencyProvidingContainer
|
||||
{
|
||||
@ -99,7 +105,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
return true;
|
||||
|
||||
case GetMessagesRequest getMessages:
|
||||
getMessages.TriggerSuccess(createChannelMessages(getMessages.Channel));
|
||||
getMessages.TriggerSuccess(initialMessages.ToList());
|
||||
return true;
|
||||
|
||||
case GetUserRequest getUser:
|
||||
@ -495,6 +501,35 @@ namespace osu.Game.Tests.Visual.Online
|
||||
waitForChannel1Visible();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRemoveMessages()
|
||||
{
|
||||
AddStep("Show overlay with channel", () =>
|
||||
{
|
||||
chatOverlay.Show();
|
||||
channelManager.CurrentChannel.Value = channelManager.JoinChannel(testChannel1);
|
||||
});
|
||||
|
||||
AddAssert("Overlay is visible", () => chatOverlay.State.Value == Visibility.Visible);
|
||||
waitForChannel1Visible();
|
||||
|
||||
AddStep("Send message from another user", () =>
|
||||
{
|
||||
testChannel1.AddNewMessages(new Message
|
||||
{
|
||||
ChannelId = testChannel1.Id,
|
||||
Content = "Message from another user",
|
||||
Timestamp = DateTimeOffset.Now,
|
||||
Sender = testUser1,
|
||||
});
|
||||
});
|
||||
|
||||
AddStep("Remove messages from other user", () =>
|
||||
{
|
||||
testChannel1.RemoveMessagesFromUser(testUser.Id);
|
||||
});
|
||||
}
|
||||
|
||||
private void joinTestChannel(int i)
|
||||
{
|
||||
AddStep($"Join test channel {i}", () => channelManager.JoinChannel(testChannels[i]));
|
||||
@ -546,7 +581,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
private List<Message> createChannelMessages(Channel channel)
|
||||
{
|
||||
var message = new Message
|
||||
var message = new Message(currentMessageId++)
|
||||
{
|
||||
ChannelId = channel.Id,
|
||||
Content = $"Hello, this is a message in {channel.Name}",
|
||||
|
@ -7,12 +7,30 @@ using osu.Game.Online.API.Requests.Responses;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
/// <summary>
|
||||
/// A request which should be sent occasionally while interested in chat and online state.
|
||||
///
|
||||
/// This will:
|
||||
/// - Mark the user as "online" (for 10 minutes since the last invocation).
|
||||
/// - Return any silences since the last invocation (if either <see cref="SinceMessageId"/> or <see cref="SinceSilenceId"/> is not null).
|
||||
///
|
||||
/// For silence handling, a <see cref="SinceMessageId"/> should be provided as soon as a message is received by the client.
|
||||
/// From that point forward, <see cref="SinceSilenceId"/> should be preferred after the first <see cref="ChatSilence"/>
|
||||
/// arrives in a response from the ack request. Specifying both parameters will prioritise the latter.
|
||||
/// </summary>
|
||||
public class ChatAckRequest : APIRequest<ChatAckResponse>
|
||||
{
|
||||
public long? SinceMessageId;
|
||||
public uint? SinceSilenceId;
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
var req = base.CreateWebRequest();
|
||||
req.Method = HttpMethod.Post;
|
||||
if (SinceMessageId != null)
|
||||
req.AddParameter(@"since", SinceMessageId.ToString());
|
||||
if (SinceSilenceId != null)
|
||||
req.AddParameter(@"history_since", SinceSilenceId.Value.ToString());
|
||||
return req;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
public uint Id { get; set; }
|
||||
|
||||
[JsonProperty("user_id")]
|
||||
public uint UserId { get; set; }
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +157,20 @@ namespace osu.Game.Online.Chat
|
||||
NewMessagesArrived?.Invoke(messages);
|
||||
}
|
||||
|
||||
public void RemoveMessagesFromUser(int userId)
|
||||
{
|
||||
for (int i = 0; i < Messages.Count; i++)
|
||||
{
|
||||
var message = Messages[i];
|
||||
|
||||
if (message.SenderId == userId)
|
||||
{
|
||||
Messages.RemoveAt(i--);
|
||||
MessageRemoved?.Invoke(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace or remove a message from the channel.
|
||||
/// </summary>
|
||||
|
@ -74,6 +74,9 @@ namespace osu.Game.Online.Chat
|
||||
private bool channelsInitialised;
|
||||
private ScheduledDelegate scheduledAck;
|
||||
|
||||
private long? lastSilenceMessageId;
|
||||
private uint? lastSilenceId;
|
||||
|
||||
public ChannelManager(IAPIProvider api)
|
||||
{
|
||||
this.api = api;
|
||||
@ -105,28 +108,7 @@ namespace osu.Game.Online.Chat
|
||||
connector.Start();
|
||||
|
||||
apiState.BindTo(api.State);
|
||||
apiState.BindValueChanged(_ => performChatAckRequest(), true);
|
||||
}
|
||||
|
||||
private void performChatAckRequest()
|
||||
{
|
||||
if (apiState.Value != APIState.Online)
|
||||
return;
|
||||
|
||||
scheduledAck?.Cancel();
|
||||
|
||||
var req = new ChatAckRequest();
|
||||
req.Success += _ => scheduleNextRequest();
|
||||
req.Failure += _ => scheduleNextRequest();
|
||||
api.Queue(req);
|
||||
|
||||
// Todo: Handle silences.
|
||||
|
||||
void scheduleNextRequest()
|
||||
{
|
||||
scheduledAck?.Cancel();
|
||||
scheduledAck = Scheduler.AddDelayed(performChatAckRequest, 60000);
|
||||
}
|
||||
apiState.BindValueChanged(_ => SendAck(), true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -349,6 +331,8 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
foreach (var group in messages.GroupBy(m => m.ChannelId))
|
||||
channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
|
||||
|
||||
lastSilenceMessageId ??= messages.LastOrDefault()?.Id;
|
||||
}
|
||||
|
||||
private void initializeChannels()
|
||||
@ -398,6 +382,44 @@ namespace osu.Game.Online.Chat
|
||||
api.Queue(fetchInitialMsgReq);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an acknowledgement request to the API.
|
||||
/// This marks the user as online to receive messages from public channels, while also returning a list of silenced users.
|
||||
/// It needs to be called at least once every 10 minutes to remain visibly marked as online.
|
||||
/// </summary>
|
||||
public void SendAck()
|
||||
{
|
||||
if (apiState.Value != APIState.Online)
|
||||
return;
|
||||
|
||||
var req = new ChatAckRequest
|
||||
{
|
||||
SinceMessageId = lastSilenceMessageId,
|
||||
SinceSilenceId = lastSilenceId
|
||||
};
|
||||
|
||||
req.Failure += _ => scheduleNextRequest();
|
||||
req.Success += ack =>
|
||||
{
|
||||
foreach (var silence in ack.Silences)
|
||||
{
|
||||
foreach (var channel in JoinedChannels)
|
||||
channel.RemoveMessagesFromUser(silence.UserId);
|
||||
lastSilenceId = Math.Max(lastSilenceId ?? 0, silence.Id);
|
||||
}
|
||||
|
||||
scheduleNextRequest();
|
||||
};
|
||||
|
||||
api.Queue(req);
|
||||
|
||||
void scheduleNextRequest()
|
||||
{
|
||||
scheduledAck?.Cancel();
|
||||
scheduledAck = Scheduler.AddDelayed(SendAck, 60000);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find an existing channel instance for the provided channel. Lookup is performed basd on ID.
|
||||
/// The provided channel may be used if an existing instance is not found.
|
||||
|
@ -72,7 +72,6 @@ namespace osu.Game.Online.Notifications.WebSocket
|
||||
break;
|
||||
}
|
||||
|
||||
Logger.Log($"{GetType().ReadableName()} handling event: {message.Event}");
|
||||
await onMessageReceivedAsync(message);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user