@@ -1,4 +1,4 @@ | |||||
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<VersionPrefix>1.0.0</VersionPrefix> | <VersionPrefix>1.0.0</VersionPrefix> | ||||
<VersionSuffix Condition="'$(BuildNumber)' == ''">rc-dev</VersionSuffix> | <VersionSuffix Condition="'$(BuildNumber)' == ''">rc-dev</VersionSuffix> | ||||
@@ -0,0 +1,9 @@ | |||||
namespace Discord | |||||
{ | |||||
public interface IRelationship | |||||
{ | |||||
RelationshipType Type { get; } | |||||
IUser User { get; } | |||||
} | |||||
} |
@@ -21,5 +21,12 @@ namespace Discord | |||||
Task<IDMChannel> GetDMChannelAsync(CacheMode mode = CacheMode.AllowDownload, RequestOptions options = null); | Task<IDMChannel> GetDMChannelAsync(CacheMode mode = CacheMode.AllowDownload, 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> CreateDMChannelAsync(RequestOptions options = null); | Task<IDMChannel> CreateDMChannelAsync(RequestOptions options = null); | ||||
/// <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); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,11 @@ | |||||
namespace Discord | |||||
{ | |||||
public enum RelationshipType | |||||
{ | |||||
None, | |||||
Friend, | |||||
Blocked, | |||||
IncomingPending, | |||||
OutgoingPending | |||||
} | |||||
} |
@@ -25,12 +25,14 @@ namespace Discord | |||||
Task<IGuild> GetGuildAsync(ulong id, CacheMode mode = CacheMode.AllowDownload); | Task<IGuild> GetGuildAsync(ulong id, CacheMode mode = CacheMode.AllowDownload); | ||||
Task<IReadOnlyCollection<IGuild>> GetGuildsAsync(CacheMode mode = CacheMode.AllowDownload); | Task<IReadOnlyCollection<IGuild>> GetGuildsAsync(CacheMode mode = CacheMode.AllowDownload); | ||||
Task<IGuild> CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null); | Task<IGuild> CreateGuildAsync(string name, IVoiceRegion region, Stream jpegIcon = null); | ||||
Task<IInvite> GetInviteAsync(string inviteId); | Task<IInvite> GetInviteAsync(string inviteId); | ||||
Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload); | Task<IUser> GetUserAsync(ulong id, CacheMode mode = CacheMode.AllowDownload); | ||||
Task<IUser> GetUserAsync(string username, string discriminator); | Task<IUser> GetUserAsync(string username, string discriminator); | ||||
Task<IReadOnlyCollection<IRelationship>> GetRelationshipsAsync(); | |||||
Task<IReadOnlyCollection<IVoiceRegion>> GetVoiceRegionsAsync(); | Task<IReadOnlyCollection<IVoiceRegion>> GetVoiceRegionsAsync(); | ||||
Task<IVoiceRegion> GetVoiceRegionAsync(string id); | Task<IVoiceRegion> GetVoiceRegionAsync(string id); | ||||
} | } | ||||
@@ -1,11 +0,0 @@ | |||||
#pragma warning disable CS1591 | |||||
namespace Discord.API | |||||
{ | |||||
internal enum RelationshipType | |||||
{ | |||||
Friend = 1, | |||||
Blocked = 2, | |||||
IncomingPending = 3, | |||||
OutgoingPending = 4 | |||||
} | |||||
} |
@@ -121,11 +121,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() | |||||
=> Task.FromResult<IReadOnlyCollection<IRelationship>>(null); | |||||
Task<IApplication> IDiscordClient.GetApplicationInfoAsync() { throw new NotSupportedException(); } | Task<IApplication> IDiscordClient.GetApplicationInfoAsync() { throw new NotSupportedException(); } | ||||
Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode) | Task<IChannel> IDiscordClient.GetChannelAsync(ulong id, CacheMode mode) | ||||
@@ -128,5 +128,11 @@ namespace Discord.Rest | |||||
var models = await client.ApiClient.GetVoiceRegionsAsync().ConfigureAwait(false); | var models = await client.ApiClient.GetVoiceRegionsAsync().ConfigureAwait(false); | ||||
return models.Select(x => RestVoiceRegion.Create(client, x)).Where(x => x.Id == id).FirstOrDefault(); | return models.Select(x => RestVoiceRegion.Create(client, x)).Where(x => x.Id == id).FirstOrDefault(); | ||||
} | } | ||||
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)).ToImmutableArray(); | |||||
} | |||||
} | } | ||||
} | } |
@@ -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(); | ||||
@@ -387,7 +387,7 @@ namespace Discord.API | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
//Channel Messages | //Channel Messages | ||||
public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) | public async Task<Message> GetChannelMessageAsync(ulong channelId, ulong messageId, RequestOptions options = null) | ||||
{ | { | ||||
@@ -678,7 +678,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) | ||||
@@ -886,14 +886,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); | ||||
} | } | ||||
@@ -1028,6 +1028,34 @@ 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) | |||||
{ | |||||
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)); | |||||
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)); | |||||
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)); | |||||
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) | ||||
@@ -1193,7 +1221,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++; | ||||
@@ -89,6 +89,9 @@ namespace Discord.Rest | |||||
public Task<RestVoiceRegion> GetVoiceRegionAsync(string id) | public Task<RestVoiceRegion> GetVoiceRegionAsync(string id) | ||||
=> ClientHelper.GetVoiceRegionAsync(this, id); | => ClientHelper.GetVoiceRegionAsync(this, id); | ||||
public Task<IReadOnlyCollection<RestRelationship>> GetRelationshipsAsync() | |||||
=> ClientHelper.GetRelationshipsAsync(this); | |||||
//IDiscordClient | //IDiscordClient | ||||
async Task<IApplication> IDiscordClient.GetApplicationInfoAsync() | async Task<IApplication> IDiscordClient.GetApplicationInfoAsync() | ||||
=> await GetApplicationInfoAsync().ConfigureAwait(false); | => await GetApplicationInfoAsync().ConfigureAwait(false); | ||||
@@ -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); | |||||
} | |||||
} | |||||
} |
@@ -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!"); | |||||
} | } | ||||
} | } |
@@ -53,6 +53,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) | |||||
=> Discord.ApiClient.AddFriendAsync(Id, options); | |||||
public Task BlockUserAsync(RequestOptions options = null) | |||||
=> Discord.ApiClient.BlockUserAsync(Id, options); | |||||
public Task RemoveRelationshipAsync(RequestOptions options = null) | |||||
=> Discord.ApiClient.RemoveRelationshipAsync(Id, options); | |||||
//IUser | //IUser | ||||
Task<IDMChannel> IUser.GetDMChannelAsync(CacheMode mode, RequestOptions options) | Task<IDMChannel> IUser.GetDMChannelAsync(CacheMode mode, RequestOptions options) | ||||
@@ -54,5 +54,12 @@ namespace Discord.Rpc | |||||
=> Task.FromResult<IDMChannel>(null); | => Task.FromResult<IDMChannel>(null); | ||||
async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) | async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) | ||||
=> await CreateDMChannelAsync(options).ConfigureAwait(false); | => await CreateDMChannelAsync(options).ConfigureAwait(false); | ||||
Task IUser.AddFriendAsync(RequestOptions options) | |||||
=> throw new NotSupportedException(); | |||||
Task IUser.BlockUserAsync(RequestOptions options) | |||||
=> throw new NotSupportedException(); | |||||
Task IUser.RemoveRelationshipAsync(RequestOptions options) | |||||
=> throw new NotSupportedException(); | |||||
} | } | ||||
} | } |
@@ -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)); | ||||
} | } | ||||
@@ -126,5 +129,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; | |||||
} | |||||
} | } | ||||
} | } |
@@ -221,5 +221,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> RelationshipAdd | |||||
{ | |||||
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>>(); | |||||
} | } | ||||
} | } |
@@ -70,6 +70,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()) { } | ||||
@@ -270,6 +271,9 @@ namespace Discord.WebSocket | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public Task<RestInvite> GetInviteAsync(string inviteId) | public Task<RestInvite> GetInviteAsync(string inviteId) | ||||
=> ClientHelper.GetInviteAsync(this, inviteId); | => ClientHelper.GetInviteAsync(this, inviteId); | ||||
public Task<IReadOnlyCollection<SocketRelationship>> GetRelationshipsAsync() | |||||
=> Task.FromResult(State.Relationships); | |||||
/// <inheritdoc /> | /// <inheritdoc /> | ||||
public SocketUser GetUser(ulong id) | public SocketUser GetUser(ulong id) | ||||
@@ -484,6 +488,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; | ||||
_unavailableGuilds = unavailableGuilds; | _unavailableGuilds = unavailableGuilds; | ||||
@@ -1499,6 +1505,29 @@ namespace Discord.WebSocket | |||||
} | } | ||||
} | } | ||||
return; | 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); | |||||
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": | ||||
@@ -1650,6 +1679,21 @@ namespace Discord.WebSocket | |||||
return channel; | return channel; | ||||
} | } | ||||
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); | |||||
} | |||||
//IDiscordClient | //IDiscordClient | ||||
ConnectionState IDiscordClient.ConnectionState => _connection.State; | ConnectionState IDiscordClient.ConnectionState => _connection.State; | ||||
@@ -1692,5 +1736,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() | |||||
=> await GetRelationshipsAsync(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,23 @@ | |||||
using Model = Discord.API.Relationship; | |||||
namespace Discord.WebSocket | |||||
{ | |||||
public class SocketRelationship : IRelationship | |||||
{ | |||||
public RelationshipType Type { get; internal 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); | |||||
} | |||||
} | |||||
} |
@@ -46,6 +46,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; | ||||
} | } | ||||
} | } |
@@ -21,6 +21,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) | ||||
@@ -55,5 +56,12 @@ namespace Discord.WebSocket | |||||
=> Task.FromResult<IDMChannel>(GlobalUser.DMChannel); | => Task.FromResult<IDMChannel>(GlobalUser.DMChannel); | ||||
async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) | async Task<IDMChannel> IUser.CreateDMChannelAsync(RequestOptions options) | ||||
=> await CreateDMChannelAsync(options).ConfigureAwait(false); | => await CreateDMChannelAsync(options).ConfigureAwait(false); | ||||
public async Task AddFriendAsync(RequestOptions options = null) | |||||
=> await Discord.ApiClient.AddFriendAsync(Id, options); | |||||
public async Task BlockUserAsync(RequestOptions options = null) | |||||
=> await Discord.ApiClient.BlockUserAsync(Id, options); | |||||
public async Task RemoveRelationshipAsync(RequestOptions options = null) | |||||
=> await Discord.ApiClient.RemoveRelationshipAsync(Id, options); | |||||
} | } | ||||
} | } |