Update socket presence and add new presence event (#1945)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
@@ -14,10 +14,10 @@ namespace Discord
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the set of clients where this user is currently active.
|
/// Gets the set of clients where this user is currently active.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IImmutableSet<ClientType> ActiveClients { get; }
|
IReadOnlyCollection<ClientType> ActiveClients { get; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the list of activities that this user currently has available.
|
/// Gets the list of activities that this user currently has available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IImmutableList<IActivity> Activities { get; }
|
IReadOnlyCollection<IActivity> Activities { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Globalization;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Model = Discord.API.User;
|
using Model = Discord.API.User;
|
||||||
using EventUserModel = Discord.API.GuildScheduledEventUser;
|
using EventUserModel = Discord.API.GuildScheduledEventUser;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Discord.Rest
|
namespace Discord.Rest
|
||||||
{
|
{
|
||||||
@@ -41,9 +42,9 @@ namespace Discord.Rest
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual UserStatus Status => UserStatus.Offline;
|
public virtual UserStatus Status => UserStatus.Offline;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual IImmutableSet<ClientType> ActiveClients => ImmutableHashSet<ClientType>.Empty;
|
public virtual IReadOnlyCollection<ClientType> ActiveClients => ImmutableHashSet<ClientType>.Empty;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual IImmutableList<IActivity> Activities => ImmutableList<IActivity>.Empty;
|
public virtual IReadOnlyCollection<IActivity> Activities => ImmutableList<IActivity>.Empty;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual bool IsWebhook => false;
|
public virtual bool IsWebhook => false;
|
||||||
|
|
||||||
|
|||||||
@@ -502,6 +502,18 @@ namespace Discord.WebSocket
|
|||||||
internal readonly AsyncEvent<Func<SocketGroupUser, Task>> _recipientRemovedEvent = new AsyncEvent<Func<SocketGroupUser, Task>>();
|
internal readonly AsyncEvent<Func<SocketGroupUser, Task>> _recipientRemovedEvent = new AsyncEvent<Func<SocketGroupUser, Task>>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Presence
|
||||||
|
|
||||||
|
/// <summary> Fired when a users presence is updated. </summary>
|
||||||
|
public event Func<SocketUser, SocketPresence, SocketPresence, Task> PresenceUpdated
|
||||||
|
{
|
||||||
|
add { _presenceUpdated.Add(value); }
|
||||||
|
remove { _presenceUpdated.Remove(value); }
|
||||||
|
}
|
||||||
|
internal readonly AsyncEvent<Func<SocketUser, SocketPresence, SocketPresence, Task>> _presenceUpdated = new AsyncEvent<Func<SocketUser, SocketPresence, SocketPresence, Task>>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Invites
|
#region Invites
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when an invite is created.
|
/// Fired when an invite is created.
|
||||||
|
|||||||
@@ -1858,6 +1858,8 @@ namespace Discord.WebSocket
|
|||||||
|
|
||||||
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
||||||
|
|
||||||
|
SocketUser user = null;
|
||||||
|
|
||||||
if (data.GuildId.IsSpecified)
|
if (data.GuildId.IsSpecified)
|
||||||
{
|
{
|
||||||
var guild = State.GetGuild(data.GuildId.Value);
|
var guild = State.GetGuild(data.GuildId.Value);
|
||||||
@@ -1872,7 +1874,7 @@ namespace Discord.WebSocket
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = guild.GetUser(data.User.Id);
|
user = guild.GetUser(data.User.Id);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
if (data.Status == UserStatus.Offline)
|
if (data.Status == UserStatus.Offline)
|
||||||
@@ -1890,26 +1892,21 @@ namespace Discord.WebSocket
|
|||||||
await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false);
|
await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var before = user.Clone();
|
|
||||||
user.Update(State, data, true);
|
|
||||||
var cacheableBefore = new Cacheable<SocketGuildUser, ulong>(before, user.Id, true, () => Task.FromResult(user));
|
|
||||||
await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var globalUser = State.GetUser(data.User.Id);
|
user = State.GetUser(data.User.Id);
|
||||||
if (globalUser == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
await UnknownGlobalUserAsync(type, data.User.Id).ConfigureAwait(false);
|
await UnknownGlobalUserAsync(type, data.User.Id).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var before = globalUser.Clone();
|
|
||||||
globalUser.Update(State, data.User);
|
|
||||||
globalUser.Update(State, data);
|
|
||||||
await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before, globalUser).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var before = user.Presence.Clone();
|
||||||
|
user.Update(State, data.User);
|
||||||
|
user.Update(data);
|
||||||
|
await TimedInvokeAsync(_presenceUpdated, nameof(PresenceUpdated), user, before, user.Presence).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "TYPING_START":
|
case "TYPING_START":
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Model = Discord.API.User;
|
using Model = Discord.API.User;
|
||||||
using PresenceModel = Discord.API.Presence;
|
|
||||||
|
|
||||||
namespace Discord.WebSocket
|
namespace Discord.WebSocket
|
||||||
{
|
{
|
||||||
@@ -48,11 +47,6 @@ namespace Discord.WebSocket
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Update(ClientState state, PresenceModel model)
|
|
||||||
{
|
|
||||||
Presence = SocketPresence.Create(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Global)";
|
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")}, Global)";
|
||||||
internal new SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser;
|
internal new SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,8 +164,7 @@ namespace Discord.WebSocket
|
|||||||
{
|
{
|
||||||
if (updatePresence)
|
if (updatePresence)
|
||||||
{
|
{
|
||||||
Presence = SocketPresence.Create(model);
|
Update(model);
|
||||||
GlobalUser.Update(state, model);
|
|
||||||
}
|
}
|
||||||
if (model.Nick.IsSpecified)
|
if (model.Nick.IsSpecified)
|
||||||
Nickname = model.Nick.Value;
|
Nickname = model.Nick.Value;
|
||||||
@@ -174,6 +173,13 @@ namespace Discord.WebSocket
|
|||||||
if (model.PremiumSince.IsSpecified)
|
if (model.PremiumSince.IsSpecified)
|
||||||
_premiumSinceTicks = model.PremiumSince.Value?.UtcTicks;
|
_premiumSinceTicks = model.PremiumSince.Value?.UtcTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal override void Update(PresenceModel model)
|
||||||
|
{
|
||||||
|
Presence.Update(model);
|
||||||
|
GlobalUser.Update(model);
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateRoles(ulong[] roleIds)
|
private void UpdateRoles(ulong[] roleIds)
|
||||||
{
|
{
|
||||||
var roles = ImmutableArray.CreateBuilder<ulong>(roleIds.Length + 1);
|
var roles = ImmutableArray.CreateBuilder<ulong>(roleIds.Length + 1);
|
||||||
|
|||||||
@@ -11,26 +11,37 @@ namespace Discord.WebSocket
|
|||||||
/// Represents the WebSocket user's presence status. This may include their online status and their activity.
|
/// Represents the WebSocket user's presence status. This may include their online status and their activity.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
[DebuggerDisplay(@"{DebuggerDisplay,nq}")]
|
||||||
public struct SocketPresence : IPresence
|
public class SocketPresence : IPresence
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public UserStatus Status { get; }
|
public UserStatus Status { get; private set; }
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IImmutableSet<ClientType> ActiveClients { get; }
|
public IReadOnlyCollection<ClientType> ActiveClients { get; private set; }
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IImmutableList<IActivity> Activities { get; }
|
public IReadOnlyCollection<IActivity> Activities { get; private set; }
|
||||||
|
|
||||||
|
internal SocketPresence() { }
|
||||||
internal SocketPresence(UserStatus status, IImmutableSet<ClientType> activeClients, IImmutableList<IActivity> activities)
|
internal SocketPresence(UserStatus status, IImmutableSet<ClientType> activeClients, IImmutableList<IActivity> activities)
|
||||||
{
|
{
|
||||||
Status = status;
|
Status = status;
|
||||||
ActiveClients = activeClients ?? ImmutableHashSet<ClientType>.Empty;
|
ActiveClients = activeClients ?? ImmutableHashSet<ClientType>.Empty;
|
||||||
Activities = activities ?? ImmutableList<IActivity>.Empty;
|
Activities = activities ?? ImmutableList<IActivity>.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SocketPresence Create(Model model)
|
internal static SocketPresence Create(Model model)
|
||||||
{
|
{
|
||||||
var clients = ConvertClientTypesDict(model.ClientStatus.GetValueOrDefault());
|
var entity = new SocketPresence();
|
||||||
var activities = ConvertActivitiesList(model.Activities);
|
entity.Update(model);
|
||||||
return new SocketPresence(model.Status, clients, activities);
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void Update(Model model)
|
||||||
|
{
|
||||||
|
Status = model.Status;
|
||||||
|
ActiveClients = ConvertClientTypesDict(model.ClientStatus.GetValueOrDefault()) ?? ImmutableArray<ClientType>.Empty;
|
||||||
|
Activities = ConvertActivitiesList(model.Activities) ?? ImmutableArray<IActivity>.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="IReadOnlyCollection{T}"/> containing all of the client types
|
/// Creates a new <see cref="IReadOnlyCollection{T}"/> containing all of the client types
|
||||||
/// where a user is active from the data supplied in the Presence update frame.
|
/// where a user is active from the data supplied in the Presence update frame.
|
||||||
@@ -42,7 +53,7 @@ namespace Discord.WebSocket
|
|||||||
/// <returns>
|
/// <returns>
|
||||||
/// A collection of all <see cref="ClientType"/>s that this user is active.
|
/// A collection of all <see cref="ClientType"/>s that this user is active.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
private static IImmutableSet<ClientType> ConvertClientTypesDict(IDictionary<string, string> clientTypesDict)
|
private static IReadOnlyCollection<ClientType> ConvertClientTypesDict(IDictionary<string, string> clientTypesDict)
|
||||||
{
|
{
|
||||||
if (clientTypesDict == null || clientTypesDict.Count == 0)
|
if (clientTypesDict == null || clientTypesDict.Count == 0)
|
||||||
return ImmutableHashSet<ClientType>.Empty;
|
return ImmutableHashSet<ClientType>.Empty;
|
||||||
@@ -84,6 +95,6 @@ namespace Discord.WebSocket
|
|||||||
public override string ToString() => Status.ToString();
|
public override string ToString() => Status.ToString();
|
||||||
private string DebuggerDisplay => $"{Status}{(Activities?.FirstOrDefault()?.Name ?? "")}";
|
private string DebuggerDisplay => $"{Status}{(Activities?.FirstOrDefault()?.Name ?? "")}";
|
||||||
|
|
||||||
internal SocketPresence Clone() => this;
|
internal SocketPresence Clone() => MemberwiseClone() as SocketPresence;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.Rest;
|
using Discord.Rest;
|
||||||
using Model = Discord.API.User;
|
using Model = Discord.API.User;
|
||||||
|
using PresenceModel = Discord.API.Presence;
|
||||||
|
|
||||||
namespace Discord.WebSocket
|
namespace Discord.WebSocket
|
||||||
{
|
{
|
||||||
@@ -40,9 +41,9 @@ namespace Discord.WebSocket
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public UserStatus Status => Presence.Status;
|
public UserStatus Status => Presence.Status;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IImmutableSet<ClientType> ActiveClients => Presence.ActiveClients ?? ImmutableHashSet<ClientType>.Empty;
|
public IReadOnlyCollection<ClientType> ActiveClients => Presence.ActiveClients ?? ImmutableHashSet<ClientType>.Empty;
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IImmutableList<IActivity> Activities => Presence.Activities ?? ImmutableList<IActivity>.Empty;
|
public IReadOnlyCollection<IActivity> Activities => Presence.Activities ?? ImmutableList<IActivity>.Empty;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets mutual guilds shared with this user.
|
/// Gets mutual guilds shared with this user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -91,6 +92,11 @@ namespace Discord.WebSocket
|
|||||||
return hasChanges;
|
return hasChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal virtual void Update(PresenceModel model)
|
||||||
|
{
|
||||||
|
Presence.Update(model);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<IDMChannel> CreateDMChannelAsync(RequestOptions options = null)
|
public async Task<IDMChannel> CreateDMChannelAsync(RequestOptions options = null)
|
||||||
=> await UserHelper.CreateDMChannelAsync(this, Discord, options).ConfigureAwait(false);
|
=> await UserHelper.CreateDMChannelAsync(this, Discord, options).ConfigureAwait(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user