Adjust ChannelManager to use notifications client

This commit is contained in:
Dan Balasescu 2022-10-28 16:22:35 +09:00
parent 33bb1212d1
commit 2f731f86ba
3 changed files with 43 additions and 95 deletions

View File

@ -48,7 +48,7 @@ namespace osu.Game.Tournament.Components
if (manager == null) if (manager == null)
{ {
AddInternal(manager = new ChannelManager(api) { HighPollRate = { Value = true } }); AddInternal(manager = new ChannelManager(api));
Channel.BindTo(manager.CurrentChannel); Channel.BindTo(manager.CurrentChannel);
} }

View File

@ -6,16 +6,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Threading;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Input;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Notifications;
using osu.Game.Overlays.Chat.Listing; using osu.Game.Overlays.Chat.Listing;
namespace osu.Game.Online.Chat namespace osu.Game.Online.Chat
@ -23,7 +24,7 @@ namespace osu.Game.Online.Chat
/// <summary> /// <summary>
/// Manages everything channel related /// Manages everything channel related
/// </summary> /// </summary>
public class ChannelManager : PollingComponent, IChannelPostTarget public class ChannelManager : CompositeComponent, IChannelPostTarget
{ {
/// <summary> /// <summary>
/// The channels the player joins on startup /// The channels the player joins on startup
@ -68,9 +69,12 @@ namespace osu.Game.Online.Chat
[Resolved] [Resolved]
private UserLookupCache users { get; set; } private UserLookupCache users { get; set; }
public readonly BindableBool HighPollRate = new BindableBool(); [Resolved]
private NotificationsClientConnector connector { get; set; }
private readonly IBindable<bool> isIdle = new BindableBool(); private readonly IBindable<APIState> apiState = new Bindable<APIState>();
private bool channelsInitialised;
private ScheduledDelegate ackDelegate;
public ChannelManager(IAPIProvider api) public ChannelManager(IAPIProvider api)
{ {
@ -78,30 +82,34 @@ namespace osu.Game.Online.Chat
CurrentChannel.ValueChanged += currentChannelChanged; CurrentChannel.ValueChanged += currentChannelChanged;
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader]
private void load(IdleTracker idleTracker) private void load()
{ {
HighPollRate.BindValueChanged(updatePollRate); connector.ChannelJoined += ch => joinChannel(ch);
isIdle.BindValueChanged(updatePollRate, true); connector.NewMessages += addMessages;
connector.PresenceReceived += () =>
if (idleTracker != null) {
isIdle.BindTo(idleTracker.IsIdle); if (!channelsInitialised)
{
channelsInitialised = true;
// we want this to run after the first presence so we can see if the user is in any channels already.
initializeChannels();
} }
};
private void updatePollRate(ValueChangedEvent<bool> valueChangedEvent) connector.StartChat();
apiState.BindTo(api.State);
apiState.BindValueChanged(status =>
{ {
// Polling will eventually be replaced with websocket, but let's avoid doing these background operations as much as possible for now. ackDelegate?.Cancel();
// The only loss will be delayed PM/message highlight notifications.
int millisecondsBetweenPolls = HighPollRate.Value ? 1000 : 60000;
if (isIdle.Value) if (status.NewValue == APIState.Online)
millisecondsBetweenPolls *= 10;
if (TimeBetweenPolls.Value != millisecondsBetweenPolls)
{ {
TimeBetweenPolls.Value = millisecondsBetweenPolls; Scheduler.Add(ackDelegate = new ScheduledDelegate(() => api.Queue(new ChatAckRequest()), 0, 60000));
Logger.Log($"Chat is now polling every {TimeBetweenPolls.Value} ms"); // Todo: Handle silences.
} }
}, true);
} }
/// <summary> /// <summary>
@ -328,7 +336,7 @@ namespace osu.Game.Online.Chat
} }
} }
private void handleChannelMessages(IEnumerable<Message> messages) private void addMessages(List<Message> messages)
{ {
var channels = JoinedChannels.ToList(); var channels = JoinedChannels.ToList();
@ -376,7 +384,7 @@ namespace osu.Game.Online.Chat
var fetchInitialMsgReq = new GetMessagesRequest(channel); var fetchInitialMsgReq = new GetMessagesRequest(channel);
fetchInitialMsgReq.Success += messages => fetchInitialMsgReq.Success += messages =>
{ {
handleChannelMessages(messages); addMessages(messages);
channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none. channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none.
}; };
@ -464,7 +472,7 @@ namespace osu.Game.Online.Chat
{ {
channel.Id = resChannel.ChannelID.Value; channel.Id = resChannel.ChannelID.Value;
handleChannelMessages(resChannel.RecentMessages); addMessages(resChannel.RecentMessages);
channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none. channel.MessagesLoaded = true; // this will mark the channel as having received messages even if there were none.
} }
}; };
@ -574,57 +582,6 @@ namespace osu.Game.Online.Chat
} }
} }
private long lastMessageId;
private bool channelsInitialised;
protected override Task Poll()
{
if (!api.IsLoggedIn)
return base.Poll();
var fetchReq = new GetUpdatesRequest(lastMessageId);
var tcs = new TaskCompletionSource<bool>();
fetchReq.Success += updates =>
{
if (updates?.Presence != null)
{
foreach (var channel in updates.Presence)
{
// we received this from the server so should mark the channel already joined.
channel.Joined.Value = true;
joinChannel(channel);
}
//todo: handle left channels
handleChannelMessages(updates.Messages);
foreach (var group in updates.Messages.GroupBy(m => m.ChannelId))
JoinedChannels.FirstOrDefault(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
lastMessageId = updates.Messages.LastOrDefault()?.Id ?? lastMessageId;
}
if (!channelsInitialised)
{
channelsInitialised = true;
// we want this to run after the first presence so we can see if the user is in any channels already.
initializeChannels();
}
tcs.SetResult(true);
};
fetchReq.Failure += _ => tcs.SetResult(false);
api.Queue(fetchReq);
return tcs.Task;
}
/// <summary> /// <summary>
/// Marks the <paramref name="channel"/> as read /// Marks the <paramref name="channel"/> as read
/// </summary> /// </summary>

View File

@ -44,6 +44,7 @@ using osu.Game.Localisation;
using osu.Game.Online; using osu.Game.Online;
using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Chat; using osu.Game.Online.Chat;
using osu.Game.Online.Notifications;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Game.Overlays.Music; using osu.Game.Overlays.Music;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
@ -83,6 +84,7 @@ namespace osu.Game
private ChatOverlay chatOverlay; private ChatOverlay chatOverlay;
private ChannelManager channelManager; private ChannelManager channelManager;
private NotificationsClientConnector notificationsClient;
[NotNull] [NotNull]
protected readonly NotificationOverlay Notifications = new NotificationOverlay(); protected readonly NotificationOverlay Notifications = new NotificationOverlay();
@ -676,6 +678,7 @@ namespace osu.Game
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
SentryLogger.Dispose(); SentryLogger.Dispose();
notificationsClient.Dispose();
} }
protected override IDictionary<FrameworkSetting, object> GetFrameworkConfigDefaults() protected override IDictionary<FrameworkSetting, object> GetFrameworkConfigDefaults()
@ -879,6 +882,7 @@ namespace osu.Game
loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true);
loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true);
var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true);
loadComponentSingleFile(notificationsClient = new NotificationsClientConnector(API), AddInternal, true);
loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true); loadComponentSingleFile(channelManager = new ChannelManager(API), AddInternal, true);
loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true);
loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true);
@ -908,19 +912,6 @@ namespace osu.Game
loadComponentSingleFile(new BackgroundBeatmapProcessor(), Add); loadComponentSingleFile(new BackgroundBeatmapProcessor(), Add);
chatOverlay.State.BindValueChanged(_ => updateChatPollRate());
// Multiplayer modes need to increase poll rate temporarily.
API.Activity.BindValueChanged(_ => updateChatPollRate(), true);
void updateChatPollRate()
{
channelManager.HighPollRate.Value =
chatOverlay.State.Value == Visibility.Visible
|| API.Activity.Value is UserActivity.InLobby
|| API.Activity.Value is UserActivity.InMultiplayerGame
|| API.Activity.Value is UserActivity.SpectatingMultiplayerGame;
}
Add(difficultyRecommender); Add(difficultyRecommender);
Add(externalLinkOpener = new ExternalLinkOpener()); Add(externalLinkOpener = new ExternalLinkOpener());
Add(new MusicKeyBindingHandler()); Add(new MusicKeyBindingHandler());