diff --git a/src/Discord.Net.Core/Entities/Users/RelationshipType.cs b/src/Discord.Net.Core/Entities/Users/RelationshipType.cs
index 71dd3eb3c..dc5129aa1 100644
--- a/src/Discord.Net.Core/Entities/Users/RelationshipType.cs
+++ b/src/Discord.Net.Core/Entities/Users/RelationshipType.cs
@@ -1,14 +1,11 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-namespace Discord
+namespace Discord
{
public enum RelationshipType
{
- Friend = 1,
- Blocked = 2,
- IncomingPending = 3,
- OutgoingPending = 4
+ None,
+ Friend,
+ Blocked,
+ IncomingPending,
+ OutgoingPending
}
}
diff --git a/src/Discord.Net.Rest/API/Common/RelationshipType.cs b/src/Discord.Net.Rest/API/Common/RelationshipType.cs
deleted file mode 100644
index 0ed99f396..000000000
--- a/src/Discord.Net.Rest/API/Common/RelationshipType.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma warning disable CS1591
-namespace Discord.API
-{
- internal enum RelationshipType
- {
- Friend = 1,
- Blocked = 2,
- IncomingPending = 3,
- OutgoingPending = 4
- }
-}
diff --git a/src/Discord.Net.Rest/BaseDiscordClient.cs b/src/Discord.Net.Rest/BaseDiscordClient.cs
index f151bfab1..f38b9506d 100644
--- a/src/Discord.Net.Rest/BaseDiscordClient.cs
+++ b/src/Discord.Net.Rest/BaseDiscordClient.cs
@@ -121,13 +121,14 @@ namespace Discord.Rest
}
///
public void Dispose() => Dispose(true);
-
- public Task> GetRelationshipsAsync() => ApiClient.GetRelationshipsAsync();
-
+
//IDiscordClient
ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected;
ISelfUser IDiscordClient.CurrentUser => CurrentUser;
-
+
+ Task> IDiscordClient.GetRelationshipsAsync()
+ => Task.FromResult>(null);
+
Task IDiscordClient.GetApplicationInfoAsync() { throw new NotSupportedException(); }
Task IDiscordClient.GetChannelAsync(ulong id, CacheMode mode)
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index 05dc8a6fc..b730745cb 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -1030,10 +1030,10 @@ namespace Discord.API
}
//Relationships
- public async Task> GetRelationshipsAsync(RequestOptions options = null)
+ public async Task> GetRelationshipsAsync(RequestOptions options = null)
{
options = RequestOptions.CreateOrClone(options);
- return await SendAsync>("GET", () => "users/@me/relationships", new BucketIds(), options: options).ConfigureAwait(false);
+ return await SendAsync>("GET", () => "users/@me/relationships", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task AddFriendAsync(ulong userId, RequestOptions options = null)
{
diff --git a/src/Discord.Net.WebSocket/ClientState.cs b/src/Discord.Net.WebSocket/ClientState.cs
index a452113e2..392791f62 100644
--- a/src/Discord.Net.WebSocket/ClientState.cs
+++ b/src/Discord.Net.WebSocket/ClientState.cs
@@ -10,11 +10,13 @@ namespace Discord.WebSocket
private const double AverageChannelsPerGuild = 10.22; //Source: Googie2149
private const double AverageUsersPerGuild = 47.78; //Source: Googie2149
private const double CollectionMultiplier = 1.05; //Add 5% buffer to handle growth
+ private const double AverageRelationshipsPerUser = 30;
private readonly ConcurrentDictionary _channels;
private readonly ConcurrentDictionary _dmChannels;
private readonly ConcurrentDictionary _guilds;
private readonly ConcurrentDictionary _users;
+ private readonly ConcurrentDictionary _relations;
private readonly ConcurrentHashSet _groupChannels;
internal IReadOnlyCollection Channels => _channels.ToReadOnlyCollection();
@@ -22,6 +24,7 @@ namespace Discord.WebSocket
internal IReadOnlyCollection GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels);
internal IReadOnlyCollection Guilds => _guilds.ToReadOnlyCollection();
internal IReadOnlyCollection Users => _users.ToReadOnlyCollection();
+ internal IReadOnlyCollection Relationships => _relations.ToReadOnlyCollection();
internal IReadOnlyCollection PrivateChannels =>
_dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat(
@@ -36,6 +39,7 @@ namespace Discord.WebSocket
_dmChannels = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier));
_guilds = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(guildCount * CollectionMultiplier));
_users = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier));
+ _relations = new ConcurrentDictionary(ConcurrentHashSet.DefaultConcurrencyLevel, (int)AverageRelationshipsPerUser);
_groupChannels = new ConcurrentHashSet(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(10 * CollectionMultiplier));
}
@@ -126,5 +130,22 @@ namespace Discord.WebSocket
return user;
return null;
}
+
+ internal SocketRelationship GetRelationship(ulong id)
+ {
+ if (_relations.TryGetValue(id, out SocketRelationship value))
+ return value;
+ return null;
+ }
+ internal void AddRelationship(SocketRelationship relation)
+ {
+ _relations[relation.User.Id] = relation;
+ }
+ internal SocketRelationship RemoveRelationship(ulong id)
+ {
+ if (_relations.TryRemove(id, out SocketRelationship value))
+ return value;
+ return null;
+ }
}
}
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs
index 313e661f3..d731e390a 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs
@@ -221,5 +221,19 @@ namespace Discord.WebSocket
remove { _recipientRemovedEvent.Remove(value); }
}
private readonly AsyncEvent> _recipientRemovedEvent = new AsyncEvent>();
+
+ // relationships
+ public event Func RelationshipAdd
+ {
+ add { _relationshipAddedEvent.Add(value); }
+ remove { _relationshipAddedEvent.Remove(value); }
+ }
+ private readonly AsyncEvent> _relationshipAddedEvent = new AsyncEvent>();
+ public event Func RelationshipRemoved
+ {
+ add { _relationshipRemovedEvent.Add(value); }
+ remove { _relationshipRemovedEvent.Remove(value); }
+ }
+ private readonly AsyncEvent> _relationshipRemovedEvent = new AsyncEvent>();
}
}
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
index 66c25e5f6..c3db1b379 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.cs
@@ -70,6 +70,7 @@ namespace Discord.WebSocket
public IReadOnlyCollection GroupChannels
=> State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray();
public IReadOnlyCollection VoiceRegions => _voiceRegions.ToReadOnlyCollection();
+ public IReadOnlyCollection Relationships => State.Relationships;
/// Creates a new REST/WebSocket discord client.
public DiscordSocketClient() : this(new DiscordSocketConfig()) { }
@@ -270,7 +271,7 @@ namespace Discord.WebSocket
///
public Task GetInviteAsync(string inviteId)
=> ClientHelper.GetInviteAsync(this, inviteId);
-
+
///
public SocketUser GetUser(ulong id)
{
@@ -484,6 +485,8 @@ namespace Discord.WebSocket
}
for (int i = 0; i < data.PrivateChannels.Length; i++)
AddPrivateChannel(data.PrivateChannels[i], state);
+ for (int i = 0; i < data.Relationships.Length; i++)
+ AddRelationship(data.Relationships[i], state);
_sessionId = data.SessionId;
_unavailableGuilds = unavailableGuilds;
@@ -1499,6 +1502,29 @@ namespace Discord.WebSocket
}
}
return;
+
+ //Relationships
+ case "RELATIONSHIP_ADD":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (RELATIONSHIP_ADD)").ConfigureAwait(false);
+
+ var addedModel = (payload as JToken).ToObject(_serializer);
+ var before = State.GetRelationship(addedModel.Id);
+ var after = AddRelationship(addedModel, State);
+
+ await _relationshipAddedEvent.InvokeAsync(before, after);
+ return;
+ }
+ case "RELATIONSHIP_REMOVE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (RELATIONSHIP_REMOVE)").ConfigureAwait(false);
+
+ var removedModel = (payload as JToken).ToObject(_serializer);
+ var removed = RemoveRelationship(removedModel.Id);
+
+ await _relationshipRemovedEvent.InvokeAsync(removed);
+ return;
+ }
//Ignored (User only)
case "CHANNEL_PINS_ACK":
@@ -1650,6 +1676,18 @@ namespace Discord.WebSocket
return channel;
}
+ internal SocketRelationship AddRelationship(Relationship model, ClientState state)
+ {
+ var relation = SocketRelationship.Create(this, state, model);
+ State.AddRelationship(relation);
+ return relation;
+ }
+ internal SocketRelationship RemoveRelationship(ulong id)
+ {
+ var relation = State.RemoveRelationship(id);
+ return relation;
+ }
+
//IDiscordClient
ConnectionState IDiscordClient.ConnectionState => _connection.State;
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs
index 1fed00801..a7bbcb805 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs
@@ -1,11 +1,23 @@
-using System;
+using Model = Discord.API.Relationship;
namespace Discord.WebSocket
{
public class SocketRelationship : IRelationship
{
- public RelationshipType Type { get; private set; }
+ public RelationshipType Type { get; internal set; }
- public IUser User { get; private set; }
+ public IUser User { get; internal set; }
+
+ public SocketRelationship(RelationshipType type, IUser user)
+ {
+ Type = type;
+ User = user;
+ }
+
+ internal static SocketRelationship Create(DiscordSocketClient discord, ClientState state, Model model)
+ {
+ SocketSimpleUser user = SocketSimpleUser.Create(discord, state, model.User);
+ return new SocketRelationship(model.Type, user);
+ }
}
}
diff --git a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs
index 5b47a1ad4..452f7f50e 100644
--- a/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs
+++ b/src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs
@@ -56,19 +56,13 @@ namespace Discord.WebSocket
async Task IUser.CreateDMChannelAsync(RequestOptions options)
=> await CreateDMChannelAsync(options).ConfigureAwait(false);
- public Task AddFriendAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
+ public async Task AddFriendAsync(RequestOptions options = null)
+ => await Discord.ApiClient.AddFriendAsync(Id, options);
- public Task BlockUserAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
+ public async Task BlockUserAsync(RequestOptions options = null)
+ => await Discord.ApiClient.BlockUserAsync(Id, options);
- public Task RemoveRelationshipAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
+ public async Task RemoveRelationshipAsync(RequestOptions options = null)
+ => await Discord.ApiClient.RemoveRelationshipAsync(Id, options);
}
}