Browse Source

Merge 985268f777 into 95b78df9f0

pull/745/merge
ObsidianMinor GitHub 8 years ago
parent
commit
02ac85771c
20 changed files with 273 additions and 23 deletions
  1. +9
    -0
      src/Discord.Net.Core/Entities/Users/IRelationship.cs
  2. +7
    -1
      src/Discord.Net.Core/Entities/Users/IUser.cs
  3. +11
    -0
      src/Discord.Net.Core/Entities/Users/RelationshipType.cs
  4. +2
    -0
      src/Discord.Net.Core/IDiscordClient.cs
  5. +2
    -0
      src/Discord.Net.Core/Utils/Preconditions.cs
  6. +0
    -11
      src/Discord.Net.Rest/API/Common/RelationshipType.cs
  7. +5
    -2
      src/Discord.Net.Rest/BaseDiscordClient.cs
  8. +15
    -0
      src/Discord.Net.Rest/ClientHelper.cs
  9. +42
    -5
      src/Discord.Net.Rest/DiscordRestApiClient.cs
  10. +3
    -0
      src/Discord.Net.Rest/DiscordRestClient.cs
  11. +26
    -0
      src/Discord.Net.Rest/Entities/Users/RestRelationship.cs
  12. +9
    -0
      src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs
  13. +7
    -0
      src/Discord.Net.Rest/Entities/Users/RestUser.cs
  14. +7
    -1
      src/Discord.Net.Rpc/Entities/Users/RpcUser.cs
  15. +20
    -0
      src/Discord.Net.WebSocket/ClientState.cs
  16. +14
    -0
      src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs
  17. +50
    -3
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  18. +27
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs
  19. +9
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs
  20. +8
    -0
      src/Discord.Net.WebSocket/Entities/Users/SocketUser.cs

+ 9
- 0
src/Discord.Net.Core/Entities/Users/IRelationship.cs View File

@@ -0,0 +1,9 @@
namespace Discord
{
public interface IRelationship
{
RelationshipType Type { get; }

IUser User { get; }
}
}

+ 7
- 1
src/Discord.Net.Core/Entities/Users/IUser.cs View File

@@ -18,7 +18,13 @@ namespace Discord
bool IsWebhook { get; } bool IsWebhook { get; }
/// <summary> Gets the username for this user. </summary> /// <summary> Gets the username for this user. </summary>
string Username { get; } string Username { get; }

/// <summary> Adds this user as a friend, this will remove a block </summary>
Task AddFriendAsync(RequestOptions options = null);
/// <summary> Blocks this user, and removes the user as a friend </summary>
Task BlockUserAsync(RequestOptions options = null);
/// <summary> Removes the relationship of this user </summary>
Task RemoveRelationshipAsync(RequestOptions options = null);
/// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary> /// <summary> Returns a private message channel to this user, creating one if it does not already exist. </summary>
Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null); Task<IDMChannel> GetOrCreateDMChannelAsync(RequestOptions options = null);
} }


+ 11
- 0
src/Discord.Net.Core/Entities/Users/RelationshipType.cs View File

@@ -0,0 +1,11 @@
namespace Discord
{
public enum RelationshipType
{
None,
Friend,
Blocked,
IncomingPending,
OutgoingPending
}
}

+ 2
- 0
src/Discord.Net.Core/IDiscordClient.cs View File

@@ -26,6 +26,8 @@ namespace Discord
Task<IGuild> GetGuildAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); Task<IGuild> GetGuildAsync(ulong id, CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
Task<IReadOnlyCollection<IGuild>> GetGuildsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); Task<IReadOnlyCollection<IGuild>> GetGuildsAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null);
Task<IGuild> CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null, RequestOptions options = null); Task<IGuild> CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null, RequestOptions options = null);

Task<IReadOnlyCollection<IRelationship>> GetRelationshipsAsync(RequestOptions options = null);
Task<IInvite> GetInviteAsync(string inviteId, RequestOptions options = null); Task<IInvite> GetInviteAsync(string inviteId, RequestOptions options = null);




+ 2
- 0
src/Discord.Net.Core/Utils/Preconditions.cs View File

@@ -192,5 +192,7 @@ namespace Discord
throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks old."); throw new ArgumentOutOfRangeException(name, "Messages must be younger than two weeks old.");
} }
} }

public static void LoggedInAs(TokenType token, TokenType existing) { if (token != existing) throw new NotSupportedException($"Must be logged in as a {token} to use this endpoint"); }
} }
} }

+ 0
- 11
src/Discord.Net.Rest/API/Common/RelationshipType.cs View File

@@ -1,11 +0,0 @@
#pragma warning disable CS1591
namespace Discord.API
{
internal enum RelationshipType
{
Friend = 1,
Blocked = 2,
IncomingPending = 3,
OutgoingPending = 4
}
}

+ 5
- 2
src/Discord.Net.Rest/BaseDiscordClient.cs View File

@@ -122,11 +122,14 @@ namespace Discord.Rest
} }
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() => Dispose(true); public void Dispose() => Dispose(true);
//IDiscordClient //IDiscordClient
ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected; ConnectionState IDiscordClient.ConnectionState => ConnectionState.Disconnected;
ISelfUser IDiscordClient.CurrentUser => CurrentUser; ISelfUser IDiscordClient.CurrentUser => CurrentUser;

Task<IReadOnlyCollection<IRelationship>> IDiscordClient.GetRelationshipsAsync(RequestOptions options)
=> Task.FromResult<IReadOnlyCollection<IRelationship>>(null);
Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) { throw new NotSupportedException(); } Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) { throw new NotSupportedException(); }


Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options) Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode, RequestOptions options)


+ 15
- 0
src/Discord.Net.Rest/ClientHelper.cs View File

@@ -152,5 +152,20 @@ namespace Discord.Rest
var models = await client.ApiClient.GetVoiceRegionsAsync(options).ConfigureAwait(false); var models = await client.ApiClient.GetVoiceRegionsAsync(options).ConfigureAwait(false);
return models.Select(x => RestVoiceRegion.Create(client, x)).FirstOrDefault(x => x.Id == id); return models.Select(x => RestVoiceRegion.Create(client, x)).FirstOrDefault(x => x.Id == id);
} }

public static async Task<IReadOnlyCollection<RestRelationship>> GetRelationshipsAsync(BaseDiscordClient client)
{
var models = await client.ApiClient.GetRelationshipsAsync().ConfigureAwait(false);
return models.Select(r => RestRelationship.Create(client, r)).ToReadOnlyCollection(models);
}

public static async Task AddFriendAsync(BaseDiscordClient client, ulong user, RequestOptions options)
=> await client.ApiClient.AddFriendAsync(user, options).ConfigureAwait(false);

public static async Task BlockUserAsync(BaseDiscordClient client, ulong user, RequestOptions options)
=> await client.ApiClient.BlockUserAsync(user, options).ConfigureAwait(false);

public static async Task RemoveRelationshipAsync(BaseDiscordClient client, ulong user, RequestOptions options)
=> await client.ApiClient.RemoveRelationshipAsync(user, options).ConfigureAwait(false);
} }
} }

+ 42
- 5
src/Discord.Net.Rest/DiscordRestApiClient.cs View File

@@ -241,7 +241,7 @@ namespace Discord.API
internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids, internal Task<TResponse> SendMultipartAsync<TResponse>(string method, Expression<Func<string>> endpointExpr, IReadOnlyDictionary<string, object> multipartArgs, BucketIds ids,
ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null) ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null, [CallerMemberName] string funcName = null)
=> SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options); => SendMultipartAsync<TResponse>(method, GetEndpoint(endpointExpr), multipartArgs, GetBucketId(ids, endpointExpr, AuthTokenType, funcName), clientBucket, options);
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
public async Task<TResponse> SendMultipartAsync<TResponse>(string method, string endpoint, IReadOnlyDictionary<string, object> multipartArgs,
string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null) string bucketId = null, ClientBucketType clientBucket = ClientBucketType.Unbucketed, RequestOptions options = null)
{ {
options = options ?? new RequestOptions(); options = options ?? new RequestOptions();
@@ -730,7 +730,7 @@ namespace Discord.API
Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name)); Preconditions.NotNullOrWhitespace(args.Name, nameof(args.Name));
Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId)); Preconditions.NotNullOrWhitespace(args.RegionId, nameof(args.RegionId));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendJsonAsync<Guild>("POST", () => "guilds", args, new BucketIds(), options: options).ConfigureAwait(false); return await SendJsonAsync<Guild>("POST", () => "guilds", args, new BucketIds(), options: options).ConfigureAwait(false);
} }
public async Task<Guild> DeleteGuildAsync(ulong guildId, RequestOptions options = null) public async Task<Guild> DeleteGuildAsync(ulong guildId, RequestOptions options = null)
@@ -940,14 +940,14 @@ namespace Discord.API
{ {
Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); return await SendAsync<Invite>("DELETE", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false);
} }
public async Task AcceptInviteAsync(string inviteId, RequestOptions options = null) public async Task AcceptInviteAsync(string inviteId, RequestOptions options = null)
{ {
Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId)); Preconditions.NotNullOrEmpty(inviteId, nameof(inviteId));
options = RequestOptions.CreateOrClone(options); options = RequestOptions.CreateOrClone(options);
await SendAsync("POST", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false); await SendAsync("POST", () => $"invites/{inviteId}", new BucketIds(), options: options).ConfigureAwait(false);
} }


@@ -1073,6 +1073,43 @@ namespace Discord.API
} }
catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; } catch (HttpException ex) when (ex.HttpCode == HttpStatusCode.NotFound) { return null; }
} }
//Relationships
public async Task<IReadOnlyCollection<Relationship>> GetRelationshipsAsync(RequestOptions options = null)
{
Preconditions.LoggedInAs(TokenType.User, AuthTokenType);

options = RequestOptions.CreateOrClone(options);

return await SendAsync<IReadOnlyCollection<Relationship>>("GET", () => "users/@me/relationships", new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task AddFriendAsync(ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.LoggedInAs(TokenType.User, AuthTokenType);

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("PUT", () => $"users/@me/relationships/{userId}", new object(), new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task BlockUserAsync(ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.LoggedInAs(TokenType.User, AuthTokenType);

options = RequestOptions.CreateOrClone(options);

await SendJsonAsync("PUT", () => $"users/@me/relationships/{userId}", new { type = 2 }, new BucketIds(), options: options).ConfigureAwait(false);
}
public async Task RemoveRelationshipAsync(ulong userId, RequestOptions options = null)
{
Preconditions.NotEqual(userId, 0, nameof(userId));
Preconditions.LoggedInAs(TokenType.User, AuthTokenType);

options = RequestOptions.CreateOrClone(options);

await SendAsync("DELETE", () => $"users/@me/relationships/{userId}", new BucketIds(), options: options).ConfigureAwait(false);
}


//Current User/DMs //Current User/DMs
public async Task<User> GetMyUserAsync(RequestOptions options = null) public async Task<User> GetMyUserAsync(RequestOptions options = null)
@@ -1246,7 +1283,7 @@ namespace Discord.API
int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1)); int argId = int.Parse(format.Substring(leftIndex + 1, rightIndex - leftIndex - 1));
string fieldName = GetFieldName(methodArgs[argId + 1]); string fieldName = GetFieldName(methodArgs[argId + 1]);
int? mappedId; int? mappedId;
mappedId = BucketIds.GetIndex(fieldName); mappedId = BucketIds.GetIndex(fieldName);
if(!mappedId.HasValue && rightIndex != endIndex && format.Length > rightIndex + 1 && format[rightIndex + 1] == '/') //Ignore the next slash if(!mappedId.HasValue && rightIndex != endIndex && format.Length > rightIndex + 1 && format[rightIndex + 1] == '/') //Ignore the next slash
rightIndex++; rightIndex++;


+ 3
- 0
src/Discord.Net.Rest/DiscordRestClient.cs View File

@@ -92,6 +92,9 @@ namespace Discord.Rest
public Task<RestVoiceRegion> GetVoiceRegionAsync(string id, RequestOptions options = null) public Task<RestVoiceRegion> GetVoiceRegionAsync(string id, RequestOptions options = null)
=> ClientHelper.GetVoiceRegionAsync(this, id, options); => ClientHelper.GetVoiceRegionAsync(this, id, options);


public Task<IReadOnlyCollection<RestRelationship>> GetRelationshipsAsync()
=> ClientHelper.GetRelationshipsAsync(this);

//IDiscordClient //IDiscordClient
async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options) async Task<IApplication> IDiscordClient.GetApplicationInfoAsync(RequestOptions options)
=> await GetApplicationInfoAsync(options).ConfigureAwait(false); => await GetApplicationInfoAsync(options).ConfigureAwait(false);


+ 26
- 0
src/Discord.Net.Rest/Entities/Users/RestRelationship.cs View File

@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using Model = Discord.API.Relationship;

namespace Discord.Rest
{
public class RestRelationship : IRelationship
{
public RelationshipType Type { get; internal set; }

public IUser User { get; internal set; }

internal RestRelationship(RelationshipType type, IUser user)
{
Type = type;
User = user;
}

internal static RestRelationship Create(BaseDiscordClient discord, Model model)
{
RestUser user = RestUser.Create(discord, model.User);
return new RestRelationship(model.Type, user);
}
}
}

+ 9
- 0
src/Discord.Net.Rest/Entities/Users/RestSelfUser.cs View File

@@ -49,5 +49,14 @@ namespace Discord.Rest
var model = await UserHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false); var model = await UserHelper.ModifyAsync(this, Discord, func, options).ConfigureAwait(false);
Update(model); Update(model);
} }

Task IUser.AddFriendAsync(RequestOptions options) =>
throw new InvalidOperationException("You can't friend yourself!");

Task IUser.BlockUserAsync(RequestOptions options) =>
throw new InvalidOperationException("You can't block yourself!");

Task IUser.RemoveRelationshipAsync(RequestOptions options) =>
throw new InvalidOperationException("You don't have any relations with yourself!");
} }
} }

+ 7
- 0
src/Discord.Net.Rest/Entities/Users/RestUser.cs View File

@@ -63,6 +63,13 @@ namespace Discord.Rest
public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})";


public Task AddFriendAsync(RequestOptions options = null)
=> ClientHelper.AddFriendAsync(Discord, Id, options);
public Task BlockUserAsync(RequestOptions options = null)
=> ClientHelper.BlockUserAsync(Discord, Id, options);
public Task RemoveRelationshipAsync(RequestOptions options = null)
=> ClientHelper.RemoveRelationshipAsync(Discord, Id, options);

//IUser //IUser
async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options) async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options)
=> await GetOrCreateDMChannelAsync(options); => await GetOrCreateDMChannelAsync(options);


+ 7
- 1
src/Discord.Net.Rpc/Entities/Users/RpcUser.cs View File

@@ -58,7 +58,13 @@ namespace Discord.Rpc
public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})";


//IUser
Task IUser.AddFriendAsync(RequestOptions options)
=> throw new NotSupportedException();
Task IUser.BlockUserAsync(RequestOptions options)
=> throw new NotSupportedException();
Task IUser.RemoveRelationshipAsync(RequestOptions options)
=> throw new NotSupportedException();

async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options) async Task<IDMChannel> IUser.GetOrCreateDMChannelAsync(RequestOptions options)
=> await GetOrCreateDMChannelAsync(options); => await GetOrCreateDMChannelAsync(options);
} }


+ 20
- 0
src/Discord.Net.WebSocket/ClientState.cs View File

@@ -15,6 +15,7 @@ namespace Discord.WebSocket
private readonly ConcurrentDictionary<ulong, SocketDMChannel> _dmChannels; private readonly ConcurrentDictionary<ulong, SocketDMChannel> _dmChannels;
private readonly ConcurrentDictionary<ulong, SocketGuild> _guilds; private readonly ConcurrentDictionary<ulong, SocketGuild> _guilds;
private readonly ConcurrentDictionary<ulong, SocketGlobalUser> _users; private readonly ConcurrentDictionary<ulong, SocketGlobalUser> _users;
private readonly ConcurrentDictionary<ulong, SocketRelationship> _relationships;
private readonly ConcurrentHashSet<ulong> _groupChannels; private readonly ConcurrentHashSet<ulong> _groupChannels;


internal IReadOnlyCollection<SocketChannel> Channels => _channels.ToReadOnlyCollection(); internal IReadOnlyCollection<SocketChannel> Channels => _channels.ToReadOnlyCollection();
@@ -22,6 +23,7 @@ namespace Discord.WebSocket
internal IReadOnlyCollection<SocketGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels); internal IReadOnlyCollection<SocketGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels);
internal IReadOnlyCollection<SocketGuild> Guilds => _guilds.ToReadOnlyCollection(); internal IReadOnlyCollection<SocketGuild> Guilds => _guilds.ToReadOnlyCollection();
internal IReadOnlyCollection<SocketGlobalUser> Users => _users.ToReadOnlyCollection(); internal IReadOnlyCollection<SocketGlobalUser> Users => _users.ToReadOnlyCollection();
internal IReadOnlyCollection<SocketRelationship> Relationships => _relationships.ToReadOnlyCollection();


internal IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels => internal IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels =>
_dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat( _dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat(
@@ -36,6 +38,7 @@ namespace Discord.WebSocket
_dmChannels = new ConcurrentDictionary<ulong, SocketDMChannel>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier)); _dmChannels = new ConcurrentDictionary<ulong, SocketDMChannel>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier));
_guilds = new ConcurrentDictionary<ulong, SocketGuild>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); _guilds = new ConcurrentDictionary<ulong, SocketGuild>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(guildCount * CollectionMultiplier));
_users = new ConcurrentDictionary<ulong, SocketGlobalUser>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); _users = new ConcurrentDictionary<ulong, SocketGlobalUser>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier));
_relationships = new ConcurrentDictionary<ulong, SocketRelationship>(ConcurrentHashSet.DefaultConcurrencyLevel, 35);
_groupChannels = new ConcurrentHashSet<ulong>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(10 * CollectionMultiplier)); _groupChannels = new ConcurrentHashSet<ulong>(ConcurrentHashSet.DefaultConcurrencyLevel, (int)(10 * CollectionMultiplier));
} }


@@ -116,5 +119,22 @@ namespace Discord.WebSocket
return user; return user;
return null; return null;
} }

internal SocketRelationship GetRelationship(ulong id)
{
if (_relationships.TryGetValue(id, out SocketRelationship value))
return value;
return null;
}
internal void AddRelationship(SocketRelationship relationship)
{
_relationships[relationship.User.Id] = relationship;
}
internal SocketRelationship RemoveRelationship(ulong id)
{
if (_relationships.TryRemove(id, out SocketRelationship value))
return value;
return null;
}
} }
} }

+ 14
- 0
src/Discord.Net.WebSocket/DiscordSocketClient.Events.cs View File

@@ -215,5 +215,19 @@ namespace Discord.WebSocket
remove { _recipientRemovedEvent.Remove(value); } remove { _recipientRemovedEvent.Remove(value); }
} }
private readonly AsyncEvent<Func<SocketGroupUser, Task>> _recipientRemovedEvent = new AsyncEvent<Func<SocketGroupUser, Task>>(); private readonly AsyncEvent<Func<SocketGroupUser, Task>> _recipientRemovedEvent = new AsyncEvent<Func<SocketGroupUser, Task>>();
// relationships
public event Func<SocketRelationship, SocketRelationship, Task> RelationshipAdded
{
add { _relationshipAddedEvent.Add(value); }
remove { _relationshipAddedEvent.Remove(value); }
}
private readonly AsyncEvent<Func<SocketRelationship, SocketRelationship, Task>> _relationshipAddedEvent = new AsyncEvent<Func<SocketRelationship, SocketRelationship, Task>>();
public event Func<SocketRelationship, Task> RelationshipRemoved
{
add { _relationshipRemovedEvent.Add(value); }
remove { _relationshipRemovedEvent.Remove(value); }
}
private readonly AsyncEvent<Func<SocketRelationship, Task>> _relationshipRemovedEvent = new AsyncEvent<Func<SocketRelationship, Task>>();
} }
} }

+ 50
- 3
src/Discord.Net.WebSocket/DiscordSocketClient.cs View File

@@ -68,6 +68,7 @@ namespace Discord.WebSocket
public IReadOnlyCollection<SocketGroupChannel> GroupChannels public IReadOnlyCollection<SocketGroupChannel> GroupChannels
=> State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray(); => State.PrivateChannels.Select(x => x as SocketGroupChannel).Where(x => x != null).ToImmutableArray();
public IReadOnlyCollection<RestVoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection(); public IReadOnlyCollection<RestVoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection();
public IReadOnlyCollection<SocketRelationship> Relationships => State.Relationships;


/// <summary> Creates a new REST/WebSocket discord client. </summary> /// <summary> Creates a new REST/WebSocket discord client. </summary>
public DiscordSocketClient() : this(new DiscordSocketConfig()) { } public DiscordSocketClient() : this(new DiscordSocketConfig()) { }
@@ -256,8 +257,11 @@ namespace Discord.WebSocket
=> ClientHelper.GetConnectionsAsync(this, new RequestOptions()); => ClientHelper.GetConnectionsAsync(this, new RequestOptions());


/// <inheritdoc /> /// <inheritdoc />
public Task<RestInvite> GetInviteAsync(string inviteId)
=> ClientHelper.GetInviteAsync(this, inviteId, new RequestOptions());
public Task<RestInvite> GetInviteAsync(string inviteId, RequestOptions options = null)
=> ClientHelper.GetInviteAsync(this, inviteId, options);
public Task<IReadOnlyCollection<SocketRelationship>> GetRelationshipsAsync()
=> Task.FromResult(State.Relationships);


/// <inheritdoc /> /// <inheritdoc />
public SocketUser GetUser(ulong id) public SocketUser GetUser(ulong id)
@@ -472,6 +476,8 @@ namespace Discord.WebSocket
} }
for (int i = 0; i < data.PrivateChannels.Length; i++) for (int i = 0; i < data.PrivateChannels.Length; i++)
AddPrivateChannel(data.PrivateChannels[i], state); AddPrivateChannel(data.PrivateChannels[i], state);
for (int i = 0; i < data.Relationships.Length; i++)
AddRelationship(data.Relationships[i], state);


_sessionId = data.SessionId; _sessionId = data.SessionId;
_unavailableGuildCount = unavailableGuilds; _unavailableGuildCount = unavailableGuilds;
@@ -1495,7 +1501,30 @@ namespace Discord.WebSocket
return; return;
} }
} }
break;
return;
//Relationships
case "RELATIONSHIP_ADD":
{
await _gatewayLogger.DebugAsync("Received Dispatch (RELATIONSHIP_ADD)").ConfigureAwait(false);

var addedModel = (payload as JToken).ToObject<Relationship>(_serializer);
var before = State.GetRelationship(addedModel.Id) ?? SocketRelationship.Create(this, State, new Relationship { Id = addedModel.Id, Type = RelationshipType.None, User = addedModel.User });
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<Relationship>(_serializer);
var removed = RemoveRelationship(removedModel.Id);

await _relationshipRemovedEvent.InvokeAsync(removed);
return;
}


//Ignored (User only) //Ignored (User only)
case "CHANNEL_PINS_ACK": case "CHANNEL_PINS_ACK":
@@ -1798,6 +1827,21 @@ namespace Discord.WebSocket
await _gatewayLogger.DebugAsync($"Unsynced Guild ({details}).").ConfigureAwait(false); await _gatewayLogger.DebugAsync($"Unsynced Guild ({details}).").ConfigureAwait(false);
} }


internal SocketRelationship GetRelationship(ulong id)
{
return State.GetRelationship(id);
}
internal SocketRelationship AddRelationship(Relationship model, ClientState state)
{
var relationship = SocketRelationship.Create(this, state, model);
state.AddRelationship(SocketRelationship.Create(this, state, model));
return relationship;
}
internal SocketRelationship RemoveRelationship(ulong id)
{
return State.RemoveRelationship(id);
}

internal int GetAudioId() => _nextAudioId++; internal int GetAudioId() => _nextAudioId++;


//IDiscordClient //IDiscordClient
@@ -1840,5 +1884,8 @@ namespace Discord.WebSocket
=> await StartAsync().ConfigureAwait(false); => await StartAsync().ConfigureAwait(false);
async Task IDiscordClient.StopAsync() async Task IDiscordClient.StopAsync()
=> await StopAsync().ConfigureAwait(false); => await StopAsync().ConfigureAwait(false);

async Task<IReadOnlyCollection<IRelationship>> IDiscordClient.GetRelationshipsAsync(RequestOptions options)
=> await GetRelationshipsAsync();
} }
} }

+ 27
- 0
src/Discord.Net.WebSocket/Entities/Users/SocketRelationship.cs View File

@@ -0,0 +1,27 @@
using System.Diagnostics;
using Model = Discord.API.Relationship;

namespace Discord.WebSocket
{
[DebuggerDisplay("{Type} - {User}")]
public class SocketRelationship : IRelationship
{
public RelationshipType Type { get; internal set; }

public IUser User { get; internal set; }

internal SocketRelationship()
{
}

internal static SocketRelationship Create(DiscordSocketClient discord, ClientState state, Model model)
{
SocketGlobalUser user = SocketGlobalUser.Create(discord, state, model.User);
return new SocketRelationship
{
Type = model.Type,
User = user
};
}
}
}

+ 9
- 0
src/Discord.Net.WebSocket/Entities/Users/SocketSelfUser.cs View File

@@ -57,6 +57,15 @@ namespace Discord.WebSocket
public Task ModifyAsync(Action<SelfUserProperties> func, RequestOptions options = null) public Task ModifyAsync(Action<SelfUserProperties> func, RequestOptions options = null)
=> UserHelper.ModifyAsync(this, Discord, func, options); => UserHelper.ModifyAsync(this, Discord, func, options);


Task IUser.AddFriendAsync(RequestOptions options) =>
throw new InvalidOperationException("You can't friend yourself!");

Task IUser.BlockUserAsync(RequestOptions options) =>
throw new InvalidOperationException("You can't block yourself!");

Task IUser.RemoveRelationshipAsync(RequestOptions options) =>
throw new InvalidOperationException("You don't have any relations with yourself!");

internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; internal new SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser;
} }
} }

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

@@ -20,6 +20,7 @@ namespace Discord.WebSocket
public string Mention => MentionUtils.MentionUser(Id); public string Mention => MentionUtils.MentionUser(Id);
public Game? Game => Presence.Game; public Game? Game => Presence.Game;
public UserStatus Status => Presence.Status; public UserStatus Status => Presence.Status;
public RelationshipType Relationship => Discord.GetRelationship(Id)?.Type ?? RelationshipType.None;


internal SocketUser(DiscordSocketClient discord, ulong id) internal SocketUser(DiscordSocketClient discord, ulong id)
: base(discord, id) : base(discord, id)
@@ -64,5 +65,12 @@ namespace Discord.WebSocket
public override string ToString() => $"{Username}#{Discriminator}"; public override string ToString() => $"{Username}#{Discriminator}";
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})"; private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id}{(IsBot ? ", Bot" : "")})";
internal SocketUser Clone() => MemberwiseClone() as SocketUser; internal SocketUser Clone() => MemberwiseClone() as SocketUser;

public async Task AddFriendAsync(RequestOptions options = null)
=> await ClientHelper.AddFriendAsync(Discord, Id, options);
public async Task BlockUserAsync(RequestOptions options = null)
=> await ClientHelper.BlockUserAsync(Discord, Id, options);
public async Task RemoveRelationshipAsync(RequestOptions options = null)
=> await ClientHelper.RemoveRelationshipAsync(Discord, Id, options);
} }
} }

Loading…
Cancel
Save