From 2f731f86bad8d71790fe0d63e400a6601b5e6408 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 28 Oct 2022 16:22:35 +0900 Subject: [PATCH] Adjust ChannelManager to use notifications client --- .../Components/TournamentMatchChatDisplay.cs | 2 +- osu.Game/Online/Chat/ChannelManager.cs | 119 ++++++------------ osu.Game/OsuGame.cs | 17 +-- 3 files changed, 43 insertions(+), 95 deletions(-) diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs index 6a8e4aa951..ca2b400e8b 100644 --- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs +++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tournament.Components if (manager == null) { - AddInternal(manager = new ChannelManager(api) { HighPollRate = { Value = true } }); + AddInternal(manager = new ChannelManager(api)); Channel.BindTo(manager.CurrentChannel); } diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ec84b0643d..b63f841f59 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -6,16 +6,17 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Graphics.Containers; using osu.Framework.Logging; +using osu.Framework.Threading; using osu.Game.Database; -using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; +using osu.Game.Online.Notifications; using osu.Game.Overlays.Chat.Listing; namespace osu.Game.Online.Chat @@ -23,7 +24,7 @@ namespace osu.Game.Online.Chat /// /// Manages everything channel related /// - public class ChannelManager : PollingComponent, IChannelPostTarget + public class ChannelManager : CompositeComponent, IChannelPostTarget { /// /// The channels the player joins on startup @@ -68,9 +69,12 @@ namespace osu.Game.Online.Chat [Resolved] private UserLookupCache users { get; set; } - public readonly BindableBool HighPollRate = new BindableBool(); + [Resolved] + private NotificationsClientConnector connector { get; set; } - private readonly IBindable isIdle = new BindableBool(); + private readonly IBindable apiState = new Bindable(); + private bool channelsInitialised; + private ScheduledDelegate ackDelegate; public ChannelManager(IAPIProvider api) { @@ -78,30 +82,34 @@ namespace osu.Game.Online.Chat CurrentChannel.ValueChanged += currentChannelChanged; } - [BackgroundDependencyLoader(permitNulls: true)] - private void load(IdleTracker idleTracker) + [BackgroundDependencyLoader] + private void load() { - HighPollRate.BindValueChanged(updatePollRate); - isIdle.BindValueChanged(updatePollRate, true); - - if (idleTracker != null) - isIdle.BindTo(idleTracker.IsIdle); - } - - private void updatePollRate(ValueChangedEvent valueChangedEvent) - { - // Polling will eventually be replaced with websocket, but let's avoid doing these background operations as much as possible for now. - // The only loss will be delayed PM/message highlight notifications. - int millisecondsBetweenPolls = HighPollRate.Value ? 1000 : 60000; - - if (isIdle.Value) - millisecondsBetweenPolls *= 10; - - if (TimeBetweenPolls.Value != millisecondsBetweenPolls) + connector.ChannelJoined += ch => joinChannel(ch); + connector.NewMessages += addMessages; + connector.PresenceReceived += () => { - TimeBetweenPolls.Value = millisecondsBetweenPolls; - Logger.Log($"Chat is now polling every {TimeBetweenPolls.Value} ms"); - } + 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(); + } + }; + + connector.StartChat(); + + apiState.BindTo(api.State); + apiState.BindValueChanged(status => + { + ackDelegate?.Cancel(); + + if (status.NewValue == APIState.Online) + { + Scheduler.Add(ackDelegate = new ScheduledDelegate(() => api.Queue(new ChatAckRequest()), 0, 60000)); + // Todo: Handle silences. + } + }, true); } /// @@ -328,7 +336,7 @@ namespace osu.Game.Online.Chat } } - private void handleChannelMessages(IEnumerable messages) + private void addMessages(List messages) { var channels = JoinedChannels.ToList(); @@ -376,7 +384,7 @@ namespace osu.Game.Online.Chat var fetchInitialMsgReq = new GetMessagesRequest(channel); fetchInitialMsgReq.Success += messages => { - handleChannelMessages(messages); + addMessages(messages); 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; - handleChannelMessages(resChannel.RecentMessages); + addMessages(resChannel.RecentMessages); 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(); - - 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; - } - /// /// Marks the as read /// diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2bdcb57f2a..7a42007fb8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -44,6 +44,7 @@ using osu.Game.Localisation; using osu.Game.Online; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; +using osu.Game.Online.Notifications; using osu.Game.Overlays; using osu.Game.Overlays.Music; using osu.Game.Overlays.Notifications; @@ -83,6 +84,7 @@ namespace osu.Game private ChatOverlay chatOverlay; private ChannelManager channelManager; + private NotificationsClientConnector notificationsClient; [NotNull] protected readonly NotificationOverlay Notifications = new NotificationOverlay(); @@ -676,6 +678,7 @@ namespace osu.Game { base.Dispose(isDisposing); SentryLogger.Dispose(); + notificationsClient.Dispose(); } protected override IDictionary GetFrameworkConfigDefaults() @@ -879,6 +882,7 @@ namespace osu.Game loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); loadComponentSingleFile(news = new NewsOverlay(), 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(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); @@ -908,19 +912,6 @@ namespace osu.Game 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(externalLinkOpener = new ExternalLinkOpener()); Add(new MusicKeyBindingHandler());