Merge remote-tracking branch 'upstream/master' into Private_Messages

This commit is contained in:
Dean Herbert
2018-11-12 20:41:10 +09:00
410 changed files with 6673 additions and 3295 deletions

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Diagnostics;
using System.Net.Http;
using osu.Framework.Configuration;
using osu.Framework.IO.Network;
@ -40,7 +41,7 @@ namespace osu.Game.Online.API
using (var req = new AccessTokenRequestPassword(username, password)
{
Url = $@"{endpoint}/oauth/token",
Method = HttpMethod.POST,
Method = HttpMethod.Post,
ClientId = clientId,
ClientSecret = clientSecret
})
@ -66,7 +67,7 @@ namespace osu.Game.Online.API
using (var req = new AccessTokenRequestRefresh(refresh)
{
Url = $@"{endpoint}/oauth/token",
Method = HttpMethod.POST,
Method = HttpMethod.Post,
ClientId = clientId,
ClientSecret = clientSecret
})

View File

@ -1,38 +1,20 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.IO.Network;
using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class GetMessagesRequest : APIMessagesRequest
public class GetMessagesRequest : APIRequest<List<Message>>
{
private readonly IEnumerable<Channel> channels;
private readonly Channel channel;
public GetMessagesRequest(IEnumerable<Channel> channels, long? sinceId) : base(sinceId)
public GetMessagesRequest(Channel channel)
{
if (channels == null)
throw new ArgumentNullException(nameof(channels));
if (channels.Any(c => c.Target != TargetType.Channel))
throw new ArgumentException($"All channels in the argument channels must have a {nameof(Channel.Target)} of {nameof(TargetType.Channel)}");
this.channels = channels;
this.channel = channel;
}
protected override WebRequest CreateWebRequest()
{
string channelString = string.Join(",", channels.Select(x => x.Id));
var req = base.CreateWebRequest();
req.AddParameter(@"channels", channelString);
return req;
}
protected override string Target => @"chat/messages";
protected override string Target => $@"chat/channels/{channel.Id}/messages";
}
}

View File

@ -0,0 +1,32 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using JetBrains.Annotations;
using osu.Framework.IO.Network;
using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class GetUpdatesRequest : APIRequest<GetUpdatesResponse>
{
private readonly long since;
private readonly Channel channel;
public GetUpdatesRequest(long sinceId, [CanBeNull] Channel channel = null)
{
this.channel = channel;
since = sinceId;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
if (channel != null) req.AddParameter(@"channel", channel.Id.ToString());
req.AddParameter(@"since", since.ToString());
return req;
}
protected override string Target => @"chat/updates";
}
}

View File

@ -0,0 +1,18 @@
// 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.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Online.Chat;
namespace osu.Game.Online.API.Requests
{
public class GetUpdatesResponse
{
[JsonProperty]
public List<Channel> Presence;
[JsonProperty]
public List<Message> Messages;
}
}

View File

@ -0,0 +1,31 @@
// 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 JoinChannelRequest : APIRequest
{
private readonly Channel channel;
private readonly User user;
public JoinChannelRequest(Channel channel, User user)
{
this.channel = channel;
this.user = user;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.Put;
return req;
}
protected override string Target => $@"chat/channels/{channel.Id}/users/{user.Id}";
}
}

View File

@ -0,0 +1,31 @@
// 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 LeaveChannelRequest : APIRequest
{
private readonly Channel channel;
private readonly User user;
public LeaveChannelRequest(Channel channel, User user)
{
this.channel = channel;
this.user = user;
}
protected override WebRequest CreateWebRequest()
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.Delete;
return req;
}
protected override string Target => $@"chat/channels/{channel.Id}/users/{user.Id}";
}
}

View File

@ -1,7 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions;
using System.Net.Http;
using osu.Framework.IO.Network;
using osu.Game.Online.Chat;
@ -20,15 +20,13 @@ namespace osu.Game.Online.API.Requests
{
var req = base.CreateWebRequest();
req.Method = HttpMethod.POST;
req.AddParameter(@"target_type", message.TargetType.GetDescription());
req.AddParameter(@"target_id", message.TargetId.ToString());
req.Method = HttpMethod.Post;
req.AddParameter(@"is_action", message.IsAction.ToString().ToLowerInvariant());
req.AddParameter(@"message", message.Content);
return req;
}
protected override string Target => @"chat/messages";
protected override string Target => $@"chat/channels/{message.ChannelId}/messages";
}
}

View File

@ -15,6 +15,12 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"beatmapset_id")]
public int OnlineBeatmapSetID { get; set; }
[JsonProperty(@"status")]
public BeatmapSetOnlineStatus Status { get; set; }
[JsonProperty(@"beatmapset")]
public APIBeatmapSet BeatmapSet { get; set; }
[JsonProperty(@"playcount")]
private int playCount { get; set; }
@ -59,11 +65,13 @@ namespace osu.Game.Online.API.Requests.Responses
Ruleset = rulesets.GetRuleset(ruleset),
StarDifficulty = starDifficulty,
OnlineBeatmapID = OnlineBeatmapID,
Version = version,
Status = Status,
BeatmapSet = new BeatmapSetInfo
{
OnlineBeatmapSetID = OnlineBeatmapSetID,
Status = BeatmapSet?.Status ?? BeatmapSetOnlineStatus.None
},
Version = version,
BaseDifficulty = new BeatmapDifficulty
{
DrainRate = drainRate,

View File

@ -20,10 +20,13 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"id")]
public int? OnlineBeatmapSetID
{
get { return onlineBeatmapSetID; }
set { onlineBeatmapSetID = value > 0 ? value : null; }
get => onlineBeatmapSetID;
set => onlineBeatmapSetID = value > 0 ? value : null;
}
[JsonProperty(@"status")]
public BeatmapSetOnlineStatus Status { get; set; }
[JsonProperty(@"preview_url")]
private string preview { get; set; }
@ -42,9 +45,6 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"storyboard")]
private bool hasStoryboard { get; set; }
[JsonProperty(@"status")]
private BeatmapSetOnlineStatus status { get; set; }
[JsonProperty(@"submitted_date")]
private DateTimeOffset submitted { get; set; }
@ -57,7 +57,7 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"user_id")]
private long creatorId
{
set { Author.Id = value; }
set => Author.Id = value;
}
[JsonProperty(@"beatmaps")]
@ -69,6 +69,7 @@ namespace osu.Game.Online.API.Requests.Responses
{
OnlineBeatmapSetID = OnlineBeatmapSetID,
Metadata = this,
Status = Status,
OnlineInfo = new BeatmapSetOnlineInfo
{
Covers = covers,
@ -76,7 +77,7 @@ namespace osu.Game.Online.API.Requests.Responses
PlayCount = playCount,
FavouriteCount = favouriteCount,
BPM = bpm,
Status = status,
Status = Status,
HasVideo = hasVideo,
HasStoryboard = hasStoryboard,
Submitted = submitted,

View File

@ -1,16 +1,14 @@
// 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.Collections.Generic;
using System.ComponentModel;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays;
using osu.Game.Overlays.Direct;
using osu.Game.Rulesets;
namespace osu.Game.Online.API.Requests
{
public class SearchBeatmapSetsRequest : APIRequest<IEnumerable<APIBeatmapSet>>
public class SearchBeatmapSetsRequest : APIRequest<SearchBeatmapSetsResponse>
{
private readonly string query;
private readonly RulesetInfo ruleset;
@ -35,6 +33,7 @@ namespace osu.Game.Online.API.Requests
public enum BeatmapSearchCategory
{
Any = 7,
[Description("Ranked & Approved")]
RankedApproved = 0,
Approved = 1,
@ -43,6 +42,7 @@ namespace osu.Game.Online.API.Requests
Qualified = 3,
Pending = 4,
Graveyard = 5,
[Description("My Maps")]
MyMaps = 6,
}

View File

@ -0,0 +1,20 @@
// 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.Collections.Generic;
using Newtonsoft.Json;
using osu.Game.Online.API.Requests.Responses;
namespace osu.Game.Online.API.Requests
{
public class SearchBeatmapSetsResponse
{
public IEnumerable<APIBeatmapSet> BeatmapSets;
/// <summary>
/// A collection of parameters which should be passed to the search endpoint to fetch the next page.
/// </summary>
[JsonProperty("cursor")]
public dynamic CursorJson;
}
}

View File

@ -47,11 +47,6 @@ namespace osu.Game.Online.Chat
/// </summary>
public event Action<Message> MessageRemoved;
/// <summary>
/// Signalles if the current user joined this channel or not. Defaults to false.
/// </summary>
public readonly Bindable<bool> Joined = new Bindable<bool>();
/// <summary>
/// Signalles whether the channels target is a private channel or public channel.
/// </summary>
@ -68,11 +63,21 @@ namespace osu.Game.Online.Chat
public string Topic;
[JsonProperty(@"type")]
public string Type;
public ChannelType Type;
[JsonProperty(@"channel_id")]
public long Id;
[JsonProperty(@"last_message_id")]
public long? LastMessageId;
/// <summary>
/// Signalles if the current user joined this channel or not. Defaults to false.
/// </summary>
public Bindable<bool> Joined = new Bindable<bool>();
public const int MAX_HISTORY = 300;
[JsonConstructor]
public Channel()
{
@ -90,6 +95,8 @@ namespace osu.Game.Online.Chat
NewMessagesArrived?.Invoke(new[] { message });
}
public bool MessagesLoaded { get; private set; }
/// <summary>
/// Adds new messages to the channel and purges old messages. Triggers the <see cref="NewMessagesArrived"/> event.
/// </summary>
@ -98,7 +105,14 @@ namespace osu.Game.Online.Chat
{
messages = messages.Except(Messages).ToArray();
if (messages.Length == 0) return;
Messages.AddRange(messages);
MessagesLoaded = true;
var maxMessageId = messages.Max(m => m.Id);
if (maxMessageId > LastMessageId)
LastMessageId = maxMessageId;
purgeOldMessages();

View File

@ -46,8 +46,7 @@ namespace osu.Game.Online.Chat
/// </summary>
public ObservableCollection<Channel> AvailableChannels { get; } = new ObservableCollection<Channel>();
private readonly IncomingMessagesHandler channelMessagesHandler;
private readonly IncomingMessagesHandler privateMessagesHandler;
/*private readonly IncomingMessagesHandler privateMessagesHandler;*/
private IAPIProvider api;
private ScheduledDelegate fetchMessagesScheduleder;
@ -56,11 +55,11 @@ namespace osu.Game.Online.Chat
{
CurrentChannel.ValueChanged += currentChannelChanged;
channelMessagesHandler = new IncomingMessagesHandler(
lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel), lastId), handleChannelMessages);
/*channelMessagesHandler = new IncomingMessagesHandler(
lastId => new GetMessagesRequest(JoinedChannels.Where(c => c.Target == TargetType.Channel)), handleChannelMessages);
privateMessagesHandler = new IncomingMessagesHandler(
lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages);
lastId => new GetPrivateMessagesRequest(lastId),handleUserMessages);*/
}
/// <summary>
@ -118,8 +117,7 @@ namespace osu.Game.Online.Chat
{
Sender = api.LocalUser.Value,
Timestamp = DateTimeOffset.Now,
TargetType = CurrentChannel.Value.Target,
TargetId = CurrentChannel.Value.Id,
ChannelId = CurrentChannel.Value.Id,
IsAction = isAction,
Content = text
};
@ -173,11 +171,11 @@ namespace osu.Game.Online.Chat
private void fetchNewMessages()
{
if (channelMessagesHandler.CanRequestNewMessages)
/*if (channelMessagesHandler.CanRequestNewMessages)
channelMessagesHandler.RequestNewMessages(api);
if (privateMessagesHandler.CanRequestNewMessages)
privateMessagesHandler.RequestNewMessages(api);
privateMessagesHandler.RequestNewMessages(api);*/
}
private void handleUserMessages(IEnumerable<Message> messages)
@ -200,7 +198,7 @@ namespace osu.Game.Online.Chat
long localUserId = api.LocalUser.Value.Id;
var outgoingGroups = messages.Where(m => m.Sender.Id == localUserId).GroupBy(m => m.TargetId);
var outgoingGroups = messages.Where(m => m.Sender.Id == localUserId).GroupBy(m => m.ChannelId);
var incomingGroups = messages.Where(m => m.Sender.Id != localUserId).GroupBy(m => m.UserId);
foreach (var group in incomingGroups)
@ -223,7 +221,7 @@ namespace osu.Game.Online.Chat
foreach (var withoutReplyGroup in withoutReplyGroups)
{
var userReq = new GetUserRequest(withoutReplyGroup.First().TargetId);
var userReq = new GetUserRequest(withoutReplyGroup.First().ChannelId);
userReq.Failure += exception => Logger.Error(exception, "Failed to get user informations.");
userReq.Success += user =>
@ -240,7 +238,7 @@ namespace osu.Game.Online.Chat
{
var channels = JoinedChannels.ToList();
foreach (var group in messages.GroupBy(m => m.TargetId))
foreach (var group in messages.GroupBy(m => m.ChannelId))
channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray());
}
@ -289,7 +287,7 @@ namespace osu.Game.Online.Chat
/// <param name="channel">The channel </param>
public void FetchInitalMessages(Channel channel)
{
var fetchInitialMsgReq = new GetMessagesRequest(new[] { channel }, null);
var fetchInitialMsgReq = new GetMessagesRequest(channel);
fetchInitialMsgReq.Success += handleChannelMessages;
fetchInitialMsgReq.Failure += exception => Logger.Error(exception, $"Failed to fetch inital messages for the channel {channel.Name}");
api.Queue(fetchInitialMsgReq);
@ -306,8 +304,8 @@ namespace osu.Game.Online.Chat
fetchMessagesScheduleder = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
break;
default:
channelMessagesHandler.CancelOngoingRequests();
privateMessagesHandler.CancelOngoingRequests();
/*channelMessagesHandler.CancelOngoingRequests();
privateMessagesHandler.CancelOngoingRequests();*/
fetchMessagesScheduleder?.Cancel();
fetchMessagesScheduleder = null;

View File

@ -0,0 +1,11 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Online.Chat
{
public enum ChannelType
{
PM,
Public
}
}

View File

@ -24,7 +24,7 @@ namespace osu.Game.Online.Chat
/// </summary>
public List<SpriteText> Parts;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos));
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos));
protected override HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
@ -53,7 +53,7 @@ namespace osu.Game.Online.Chat
this.parts = parts;
}
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceiveMouseInputAt(screenSpacePos));
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos));
}
}
}

View File

@ -15,11 +15,7 @@ namespace osu.Game.Online.Chat
Timestamp = DateTimeOffset.Now;
Content = message;
Sender = new User
{
Username = @"system",
Colour = @"0000ff",
};
Sender = User.SYSTEM_USER;
}
}
}

View File

@ -16,13 +16,10 @@ namespace osu.Game.Online.Chat
//todo: this should be inside sender.
[JsonProperty(@"sender_id")]
public int UserId;
public long UserId;
[JsonProperty(@"target_type")]
public TargetType TargetType;
[JsonProperty(@"target_id")]
public long TargetId;
[JsonProperty(@"channel_id")]
public long ChannelId;
[JsonProperty(@"is_action")]
public bool IsAction;