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

Add support for creating new PM conversations

This commit is contained in:
Dean Herbert 2018-11-13 17:24:11 +09:00
parent 82ebc74eee
commit 72ae22b0c4
4 changed files with 150 additions and 35 deletions

View File

@ -0,0 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Net.Http;
using osu.Framework.IO.Network;
using osu.Game.Online.Chat;
using osu.Game.Users;
namespace osu.Game.Online.API.Requests
{
public class CreateNewPrivateMessageRequest : APIRequest<CreateNewPrivateMessageResponse>
{
private readonly User user;
private readonly Message message;
public CreateNewPrivateMessageRequest(User user, Message message)
{
this.user = user;
this.message = message;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.Post;
req.AddParameter(@"target_id", user.Id.ToString());
req.AddParameter(@"message", message.Content);
req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant());
return req;
}
protected override string Target => @"chat/new";
}
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class CreateNewPrivateMessageResponse
{
[JsonProperty("new_channel_id")]
public int ChannelID;
public Message Message;
}
}

View File

@ -100,7 +100,7 @@ namespace osu.Game.Online.Chat
NewMessagesArrived?.Invoke(new[] { message });
}
public bool MessagesLoaded { get; private set; }
public bool MessagesLoaded;
/// <summary>
/// Adds new messages to the channel and purges old messages. Triggers the <see cref="NewMessagesArrived"/> event.
@ -113,7 +113,6 @@ namespace osu.Game.Online.Chat
if (messages.Length == 0) return;
Messages.AddRange(messages);
MessagesLoaded = true;
var maxMessageId = messages.Max(m => m.Id);
if (maxMessageId > LastMessageId)

View File

@ -88,6 +88,12 @@ namespace osu.Game.Online.Chat
JoinChannel(channel);
}
/// <summary>
/// Ensure we run post actions in sequence, once at a time.
/// </summary>
private readonly Queue<Action> postQueue = new Queue<Action>();
/// <summary>
/// Posts a message to the currently opened channel.
/// </summary>
@ -100,31 +106,70 @@ namespace osu.Game.Online.Chat
var currentChannel = CurrentChannel.Value;
if (!api.IsLoggedIn)
void dequeueAndRun()
{
currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!"));
return;
if (postQueue.Count > 0)
postQueue.Dequeue().Invoke();
}
var message = new LocalEchoMessage
postQueue.Enqueue(() =>
{
Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
ChannelId = CurrentChannel.Value.Id,
IsAction = isAction,
Content = text
};
if (!api.IsLoggedIn)
{
currentChannel.AddNewMessages(new ErrorMessage("Please sign in to participate in chat!"));
return;
}
currentChannel.AddLocalEcho(message);
var message = new LocalEchoMessage
{
Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
ChannelId = CurrentChannel.Value.Id,
IsAction = isAction,
Content = text
};
var req = new PostMessageRequest(message);
req.Failure += exception =>
{
Logger.Error(exception, "Posting message failed.");
currentChannel.ReplaceMessage(message, null);
};
req.Success += m => currentChannel.ReplaceMessage(message, m);
api.Queue(req);
currentChannel.AddLocalEcho(message);
// if this is a PM and the first message, we need to do a special request to create the PM channel
if (currentChannel.Type == ChannelType.PM && !currentChannel.Joined)
{
var createNewPrivateMessageRequest = new CreateNewPrivateMessageRequest(currentChannel.Users.First(), message);
createNewPrivateMessageRequest.Success += createRes =>
{
currentChannel.Id = createRes.ChannelID;
currentChannel.ReplaceMessage(message, createRes.Message);
dequeueAndRun();
};
createNewPrivateMessageRequest.Failure += exception =>
{
Logger.Error(exception, "Posting message failed.");
currentChannel.ReplaceMessage(message, null);
dequeueAndRun();
};
api.Queue(createNewPrivateMessageRequest);
return;
}
var req = new PostMessageRequest(message);
req.Success += m =>
{
currentChannel.ReplaceMessage(message, m);
dequeueAndRun();
};
req.Failure += exception =>
{
Logger.Error(exception, "Posting message failed.");
currentChannel.ReplaceMessage(message, null);
dequeueAndRun();
};
api.Queue(req);
});
// always run if the queue is empty
if (postQueue.Count == 1)
dequeueAndRun();
}
/// <summary>
@ -170,11 +215,11 @@ namespace osu.Game.Online.Chat
channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
}
private void initializeDefaultChannels()
private void initializeChannels()
{
var req = new ListChannelsRequest();
//var joinDefaults = JoinedChannels.Count == 0;
var joinDefaults = JoinedChannels.Count == 0;
req.Success += channels =>
{
@ -185,14 +230,14 @@ namespace osu.Game.Online.Chat
AvailableChannels.Add(channel);
// join any channels classified as "defaults"
/*if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase)))
JoinChannel(channel);*/
if (joinDefaults && defaultChannels.Any(c => c.Equals(channel.Name, StringComparison.OrdinalIgnoreCase)))
JoinChannel(channel);
}
};
req.Failure += error =>
{
Logger.Error(error, "Fetching channel list failed");
initializeDefaultChannels();
initializeChannels();
};
api.Queue(req);
@ -207,9 +252,15 @@ namespace osu.Game.Online.Chat
/// <param name="channel">The channel </param>
private void fetchInitalMessages(Channel channel)
{
if (channel.Id <= 0) return;
var fetchInitialMsgReq = new GetMessagesRequest(channel);
fetchInitialMsgReq.Success += handleChannelMessages;
fetchInitialMsgReq.Failure += exception => Logger.Error(exception, $"Failed to fetch inital messages for the channel {channel.Name}");
fetchInitialMsgReq.Success += messages =>
{
handleChannelMessages(messages);
channel.MessagesLoaded = true; // this will mark the channel as having received messages even if tehre were none.
};
api.Queue(fetchInitialMsgReq);
}
@ -236,7 +287,11 @@ namespace osu.Game.Online.Chat
if (channel.Type == ChannelType.Public && !channel.Joined)
{
var req = new JoinChannelRequest(channel, api.LocalUser);
req.Success += () => JoinChannel(channel);
req.Success += () =>
{
channel.Joined.Value = true;
JoinChannel(channel);
};
req.Failure += ex => LeaveChannel(channel);
api.Queue(req);
return;
@ -246,11 +301,10 @@ namespace osu.Game.Online.Chat
if (CurrentChannel.Value == null)
CurrentChannel.Value = channel;
if (!channel.Joined.Value)
if (!channel.MessagesLoaded)
{
// let's fetch a small number of messages to bring us up-to-date with the backlog.
fetchInitalMessages(channel);
channel.Joined.Value = true;
}
}
@ -274,9 +328,6 @@ namespace osu.Game.Online.Chat
switch (state)
{
case APIState.Online:
if (JoinedChannels.Count == 0)
initializeDefaultChannels();
fetchUpdates();
break;
default:
@ -289,6 +340,8 @@ namespace osu.Game.Online.Chat
private long lastMessageId;
private const int update_poll_interval = 1000;
private bool channelsInitialised;
private void fetchUpdates()
{
fetchMessagesScheduleder?.Cancel();
@ -302,7 +355,20 @@ namespace osu.Game.Online.Chat
{
foreach (var channel in updates.Presence)
{
JoinChannel(AvailableChannels.FirstOrDefault(c => c.Id == channel.Id) ?? channel);
if (!channel.Joined.Value)
{
// we received this from the server so should mark the channel already joined.
channel.Joined.Value = true;
JoinChannel(channel);
}
}
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();
}
//todo: handle left channels