Browse Source

Update socket presence and add new presence event (#1945)

tags/3.0.0
Quin Lynch GitHub 3 years ago
parent
commit
9d6dc6279d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 37 deletions
  1. +3
    -3
      src/Discord.Net.Core/Entities/Users/IPresence.cs
  2. +3
    -2
      src/Discord.Net.Rest/Entities/Users/RestUser.cs
  3. +12
    -0
      src/Discord.Net.WebSocket/BaseSocketClient.Events.cs
  4. +10
    -13
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  5. +0
    -6
      src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs
  6. +8
    -2
      src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs
  7. +20
    -9
      src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs
  8. +8
    -2
      src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs

+ 3
- 3
src/Discord.Net.Core/Entities/Users/IPresence.cs View File

@@ -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; }
} }
} }

+ 3
- 2
src/Discord.Net.Rest/Entities/Users/RestUser.cs View File

@@ -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;




+ 12
- 0
src/Discord.Net.WebSocket/BaseSocketClient.Events.cs View File

@@ -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.


+ 10
- 13
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -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);
if (globalUser == null)
user = State.GetUser(data.User.Id);
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":


+ 0
- 6
src/Discord.Net.WebSocket/Entities/Users/SocketGlobalUser.cs View File

@@ -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;
} }


+ 8
- 2
src/Discord.Net.WebSocket/Entities/Users/SocketGuildUser.cs View File

@@ -164,8 +164,7 @@ namespace Discord.WebSocket
{ {
if (updatePresence) if (updatePresence)
{ {
Presence = SocketPresence.Create(model);
GlobalUser.Update(state, model);
Update(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);


+ 20
- 9
src/Discord.Net.WebSocket/Entities/Users/SocketPresence.cs View File

@@ -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 activities = ConvertActivitiesList(model.Activities);
return new SocketPresence(model.Status, clients, activities);
var entity = new SocketPresence();
entity.Update(model);
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;
} }
} }

+ 8
- 2
src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs View File

@@ -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);


Loading…
Cancel
Save