diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 57f55492ad..9b76c31c80 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -47,13 +47,17 @@ public class ChannelManager : Component, IOnlineComponent /// public ObservableCollection AvailableChannels { get; } = new ObservableCollection(); + private readonly IncomingMessagesHandler channelMessagesHandler; + private readonly IncomingMessagesHandler privateMessagesHandler; + private IAPIProvider api; private ScheduledDelegate fetchMessagesScheduleder; - private GetMessagesRequest fetchMessageReq; - private GetPrivateMessagesRequest fetchUserMsgReq; - private long? lastChannelMsgId; - private long? lastUserMsgId; + /// + /// Opens a channel or switches to the channel if already opened. + /// + /// If the name of the specifed channel was not found this exception will be thrown. + /// public void OpenChannel(string name) { if (name == null) @@ -63,7 +67,11 @@ public void OpenChannel(string name) ?? throw new ChannelNotFoundException(name); } - public void OpenUserChannel(User user) + /// + /// Opens a new private channel. + /// + /// + public void OpenPrivateChannel(User user) { if (user == null) throw new ArgumentNullException(nameof(user)); @@ -75,6 +83,14 @@ public void OpenUserChannel(User user) public ChannelManager() { CurrentChannel.ValueChanged += currentChannelChanged; + + channelMessagesHandler = new IncomingMessagesHandler(); + channelMessagesHandler.CreateMessagesRequest = () => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), channelMessagesHandler.LastMessageId); + channelMessagesHandler.OnNewMessages = handleChannelMessages; + + privateMessagesHandler = new IncomingMessagesHandler(); + privateMessagesHandler.CreateMessagesRequest = () => new GetPrivateMessagesRequest(privateMessagesHandler.LastMessageId); + privateMessagesHandler.OnNewMessages = handleUserMessages; } private void currentChannelChanged(Channel channel) @@ -156,32 +172,11 @@ public void PostCommand(string text) private void fetchNewMessages() { - if (fetchMessageReq == null) - fetchMessages( - () => fetchMessageReq = new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastChannelMsgId), - messages => - { - if (messages == null) - return; - handleChannelMessages(messages); - lastChannelMsgId = messages.LastOrDefault()?.Id ?? lastChannelMsgId; - fetchMessageReq = null; - } - ); + if (channelMessagesHandler.CanRequestNewMessages) + channelMessagesHandler.RequestNewMessages(api); - - if (fetchUserMsgReq == null) - fetchMessages( - () => fetchUserMsgReq = new GetPrivateMessagesRequest(lastUserMsgId), - messages => - { - if (messages == null) - return; - handleUserMessages(messages); - lastUserMsgId = messages.Max(m => m.Id) ?? lastUserMsgId; - fetchUserMsgReq = null; - } - ); + if (privateMessagesHandler.CanRequestNewMessages) + privateMessagesHandler.RequestNewMessages(api); } private void fetchMessages(Func messagesRequest, Action> handler) @@ -272,7 +267,7 @@ private void initializeDefaultChannels() channels.Where(channel => AvailableChannels.All(c => c.Id != channel.Id)) .ForEach(channel => AvailableChannels.Add(channel)); - channels.Where(channel => defaultChannels.Contains(channel.Name)) + channels.Where(channel => defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase))) .Where(channel => JoinedChannels.All(c => c.Id != channel.Id)) .ForEach(channel => { @@ -286,7 +281,12 @@ private void initializeDefaultChannels() fetchNewMessages(); }; - req.Failure += error => Logger.Error(error, "Fetching channel list failed"); + req.Failure += error => + { + Logger.Error(error, "Fetching channel list failed"); + + initializeDefaultChannels(); + }; api.Queue(req); } @@ -298,12 +298,15 @@ public void APIStateChanged(APIAccess api, APIState state) case APIState.Online: if (JoinedChannels.Count == 0) initializeDefaultChannels(); + fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true); break; default: - fetchMessageReq?.Cancel(); - fetchMessageReq = null; + channelMessagesHandler.CancelOngoingRequests(); + privateMessagesHandler.CancelOngoingRequests(); + fetchMessagesScheduleder?.Cancel(); + fetchMessagesScheduleder = null; break; } } diff --git a/osu.Game/Online/Chat/IncomingMessagesHandler.cs b/osu.Game/Online/Chat/IncomingMessagesHandler.cs new file mode 100644 index 0000000000..dc2e1cdf6b --- /dev/null +++ b/osu.Game/Online/Chat/IncomingMessagesHandler.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Logging; +using osu.Game.Online.API; + +namespace osu.Game.Online.Chat +{ + public class IncomingMessagesHandler + { + public long? LastMessageId { get; private set; } + + private APIMessagesRequest getMessagesRequest; + + public Func CreateMessagesRequest { set; private get; } + + public Action> OnNewMessages { set; private get; } + + public bool CanRequestNewMessages => getMessagesRequest == null; + + public void RequestNewMessages(IAPIProvider api) + { + if (!CanRequestNewMessages) + throw new InvalidOperationException("Requesting new messages is not possible yet, because the old request is still ongoing."); + + if (OnNewMessages == null) + throw new InvalidOperationException($"You need to set an handler for the new incoming messages ({nameof(OnNewMessages)}) first before using {nameof(RequestNewMessages)}."); + + getMessagesRequest = CreateMessagesRequest.Invoke(); + + getMessagesRequest.Success += handleNewMessages; + getMessagesRequest.Failure += exception => + { + Logger.Error(exception, "Fetching messages failed."); + + //allowing new messages to be requested even after the fail. + getMessagesRequest = null; + }; + + api.Queue(getMessagesRequest); + } + + private void handleNewMessages(List messages) + { + + //allowing new messages to be requested. + getMessagesRequest = null; + + //in case of no new messages we simply do nothing. + if (messages == null || messages.Count == 0) + return; + + OnNewMessages.Invoke(messages); + + LastMessageId = messages.Max(m => m.Id) ?? LastMessageId; + } + + public void CancelOngoingRequests() + { + getMessagesRequest?.Cancel(); + } + } +}