Browse Source

Added SocketGuildInvites

pull/1585/head
quinchs 5 years ago
parent
commit
dde4ef9e19
9 changed files with 372 additions and 3 deletions
  1. +32
    -0
      src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs
  2. +19
    -0
      src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs
  3. +16
    -0
      src/Discord.Net.WebSocket/BaseSocketClient.Events.cs
  4. +69
    -3
      src/Discord.Net.WebSocket/DiscordSocketClient.cs
  5. +18
    -0
      src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs
  6. +42
    -0
      src/Discord.Net.WebSocket/Entities/Invites/ISocketInvite.cs
  7. +47
    -0
      src/Discord.Net.WebSocket/Entities/Invites/InviteCache.cs
  8. +112
    -0
      src/Discord.Net.WebSocket/Entities/Invites/SocketGuildInvite.cs
  9. +17
    -0
      src/Discord.Net.WebSocket/Entities/Invites/SocketInviteHelper.cs

+ 32
- 0
src/Discord.Net.WebSocket/API/Gateway/InviteCreatedEvent.cs View File

@@ -0,0 +1,32 @@
using Discord.API;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.API.Gateway
{
internal class InviteCreatedEvent
{
[JsonProperty("channel_id")]
public ulong ChannelID { get; set; }
[JsonProperty("code")]
public string InviteCode { get; set; }
[JsonProperty("timestamp")]
public Optional<DateTimeOffset> RawTimestamp { get; set; }
[JsonProperty("guild_id")]
public ulong? GuildID { get; set; }
[JsonProperty("inviter")]
public Optional<User> inviter { get; set; }
[JsonProperty("max_age")]
public int RawAge { get; set; }
[JsonProperty("max_uses")]
public int MaxUsers { get; set; }
[JsonProperty("temporary")]
public bool TempInvite { get; set; }
[JsonProperty("uses")]
public int Uses { get; set; }
}
}

+ 19
- 0
src/Discord.Net.WebSocket/API/Gateway/InviteDeletedEvent.cs View File

@@ -0,0 +1,19 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.WebSocket
{
internal class InviteDeletedEvent
{
[JsonProperty("channel_id")]
public ulong ChannelID { get; set; }
[JsonProperty("guild_id")]
public Optional<ulong> GuildID { get; set; }
[JsonProperty("code")]
public string Code { get; set; }
}
}

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

@@ -315,6 +315,22 @@ namespace Discord.WebSocket
}
internal readonly AsyncEvent<Func<SocketGuild, SocketGuild, Task>> _guildUpdatedEvent = new AsyncEvent<Func<SocketGuild, SocketGuild, Task>>();

//Invites
internal readonly AsyncEvent<Func<SocketGuildInvite, Task>> _inviteCreatedEvent = new AsyncEvent<Func<SocketGuildInvite, Task>>();
/// <summary> Fired when a invite is created. </summary>
public event Func<SocketGuildInvite, Task> InviteCreated
{
add { _inviteCreatedEvent.Add(value); }
remove { _inviteCreatedEvent.Remove(value); }
}
internal readonly AsyncEvent<Func<Cacheable<SocketGuildInvite, string>, Task>> _inviteDeletedEvent = new AsyncEvent<Func<Cacheable<SocketGuildInvite, string>, Task>>();
/// <summary> Fired when a invite is deleted. </summary>
public event Func<Cacheable<SocketGuildInvite, string>, Task> InviteDeleted
{
add { _inviteDeletedEvent.Add(value); }
remove { _inviteDeletedEvent.Remove(value); }
}

//Users
/// <summary> Fired when a user joins a guild. </summary>
public event Func<SocketGuildUser, Task> UserJoined {


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

@@ -275,7 +275,8 @@ namespace Discord.WebSocket
await heartbeatTask.ConfigureAwait(false);
_heartbeatTask = null;

while (_heartbeatTimes.TryDequeue(out _)) { }
while (_heartbeatTimes.TryDequeue(out _))
{ }
_lastMessageTime = 0;

await _gatewayLogger.DebugAsync("Waiting for guild downloader").ConfigureAwait(false);
@@ -286,7 +287,8 @@ namespace Discord.WebSocket

//Clear large guild queue
await _gatewayLogger.DebugAsync("Clearing large guild queue").ConfigureAwait(false);
while (_largeGuilds.TryDequeue(out _)) { }
while (_largeGuilds.TryDequeue(out _))
{ }

//Raise virtual GUILD_UNAVAILABLEs
await _gatewayLogger.DebugAsync("Raising virtual GuildUnavailables").ConfigureAwait(false);
@@ -578,7 +580,7 @@ namespace Discord.WebSocket
}
else if (_connection.CancelToken.IsCancellationRequested)
return;
if (BaseConfig.AlwaysDownloadUsers)
_ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers));

@@ -1680,6 +1682,70 @@ namespace Discord.WebSocket

}
break;
case "INVITE_CREATE":
{
await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false);
var data = (payload as JToken).ToObject<InviteCreatedEvent>(_serializer);
if(data.GuildID.HasValue)
{
var guild = State.GetGuild(data.GuildID.Value);
if (guild != null)
{
if (!guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var channel = guild.GetChannel(data.ChannelID);

if (channel != null)
{
var invite = new SocketGuildInvite(this, guild, channel, data.InviteCode, data);
guild.AddSocketInvite(invite);
await TimedInvokeAsync(_inviteCreatedEvent, nameof(InviteCreated), invite).ConfigureAwait(false);
}
}
else
{
//add else
}
}

}
break;
case "INVITE_DELETE":
{
await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_DELETE)").ConfigureAwait(false);
var data = (payload as JToken).ToObject<InviteDeletedEvent>(_serializer);
if(data.GuildID.IsSpecified)
{
var guild = State.GetGuild(data.GuildID.Value);
if (guild != null)
{
if (!guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}

var channel = guild.GetChannel(data.ChannelID);

if (channel != null)
{
var invite = guild.RemoveSocketInvite(data.Code);
var cache = new Cacheable<SocketGuildInvite, string>(null, data.Code, invite != null, async () => await guild.GetSocketInviteAsync(data.Code));
await TimedInvokeAsync(_inviteDeletedEvent, nameof(InviteDeleted), cache).ConfigureAwait(false);
}
}
else
{
//add else
}
}

}
break;

//Ignored (User only)
case "CHANNEL_PINS_ACK":


+ 18
- 0
src/Discord.Net.WebSocket/Entities/Guilds/SocketGuild.cs View File

@@ -39,6 +39,7 @@ namespace Discord.WebSocket
private ImmutableArray<GuildEmote> _emotes;
private ImmutableArray<string> _features;
private AudioClient _audioClient;
private InviteCache _invites;
#pragma warning restore IDISP002, IDISP006

/// <inheritdoc />
@@ -280,6 +281,7 @@ namespace Discord.WebSocket
_audioLock = new SemaphoreSlim(1, 1);
_emotes = ImmutableArray.Create<GuildEmote>();
_features = ImmutableArray.Create<string>();
_invites = new InviteCache(client);
}
internal static SocketGuild Create(DiscordSocketClient discord, ClientState state, ExtendedModel model)
{
@@ -515,6 +517,22 @@ namespace Discord.WebSocket
public Task RemoveBanAsync(ulong userId, RequestOptions options = null)
=> GuildHelper.RemoveBanAsync(this, Discord, userId, options);

//Invites
internal void AddSocketInvite(SocketGuildInvite invite)
=> _invites.Add(invite);
internal SocketGuildInvite RemoveSocketInvite(string code)
=> _invites.Remove(code);
internal async Task<SocketGuildInvite> GetSocketInviteAsync(string code)
{
var invites = await this.GetInvitesAsync();
RestInviteMetadata restInvite = invites.First(x => x.Code == code);
if (restInvite == null)
return null;
var invite = new SocketGuildInvite(Discord, this, this.GetChannel(restInvite.ChannelId), code, restInvite);
return invite;
}

//Channels
/// <summary>
/// Gets a channel in this guild.


+ 42
- 0
src/Discord.Net.WebSocket/Entities/Invites/ISocketInvite.cs View File

@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.WebSocket
{
public interface ISocketInvite
{
/// <summary>
/// Gets the unique identifier for this invite.
/// </summary>
/// <returns>
/// A string containing the invite code (e.g. <c>FTqNnyS</c>).
/// </returns>
string Code { get; }
/// <summary>
/// Gets the URL used to accept this invite using <see cref="Code"/>.
/// </summary>
/// <returns>
/// A string containing the full invite URL (e.g. <c>https://discord.gg/FTqNnyS</c>).
/// </returns>
string Url { get; }

/// <summary>
/// Gets the channel this invite is linked to.
/// </summary>
/// <returns>
/// A generic channel that the invite points to.
/// </returns>
SocketGuildChannel Channel { get; }
/// <summary>
/// Gets the guild this invite is linked to.
/// </summary>
/// <returns>
/// A guild object representing the guild that the invite points to.
/// </returns>
SocketGuild Guild { get; }
}
}

+ 47
- 0
src/Discord.Net.WebSocket/Entities/Invites/InviteCache.cs View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.WebSocket
{
internal class InviteCache
{
private readonly ConcurrentDictionary<string, SocketGuildInvite> _invites;
private readonly ConcurrentQueue<string> _queue;
private static int _size;

public InviteCache(DiscordSocketClient client)
{
//NOTE:
//This should be an option in the client config.
_size = client.Guilds.Count * 20;

_invites = new ConcurrentDictionary<string, SocketGuildInvite>();
_queue = new ConcurrentQueue<string>();
}
public void Add(SocketGuildInvite invite)
{
if(_invites.TryAdd(invite.Code, invite))
{
_queue.Enqueue(invite.Code);

while (_queue.Count > _size && _queue.TryDequeue(out string invCode))
_invites.TryRemove(invCode, out _);
}
}
public SocketGuildInvite Remove(string inviteCode)
{
_invites.TryRemove(inviteCode, out SocketGuildInvite inv);
return inv;
}
public SocketGuildInvite Get(string inviteCode)
{
if(_invites.TryGetValue(inviteCode, out SocketGuildInvite inv))
return inv;
return null;
}
}
}

+ 112
- 0
src/Discord.Net.WebSocket/Entities/Invites/SocketGuildInvite.cs View File

@@ -0,0 +1,112 @@
using Discord.Rest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Threading.Tasks;
using InviteUpdate = Discord.API.Gateway.InviteCreatedEvent;

namespace Discord.WebSocket
{
/// <summary>
/// Represents a guild invite
/// </summary>
public class SocketGuildInvite : SocketEntity<string>, ISocketInvite
{
public string Code { get; private set; }
public string Url => $"{DiscordConfig.InviteUrl}{Code}";
public SocketGuildChannel Channel { get; private set; }
public SocketGuild Guild { get; private set; }
/// <summary>
/// Gets the unique invite code
/// <returns>
/// Returns the unique invite code
/// </returns>
/// </summary>
public string Id => Code;
/// <summary>
/// Gets the user who created the invite
/// <returns>
/// Returns the user who created the invite
/// </returns>
/// </summary>
public SocketGuildUser Inviter { get; private set; }
/// <summary>
/// Gets the maximum number of times the invite can be used, if there is no limit then the value will be 0
/// <returns>
/// Returns the maximum number of times the invite can be used, if there is no limit then the value will be 0
/// </returns>
/// </summary>
public int? MaxUses { get; private set; }
/// <summary>
/// Gets whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role)
/// <returns>
/// Returns whether or not the invite is temporary (invited users will be kicked on disconnect unless they're assigned a role)
/// </returns>
/// </summary>
public bool Temporary { get; private set; }
/// <summary>
/// Gets the time at which the invite was created
/// <returns>
/// Returns the time at which the invite was created
/// </returns>
/// </summary>
public DateTimeOffset? CreatedAt { get; private set; }
/// <summary>
/// Gets how long the invite is valid for
/// <returns>
/// Returns how long the invite is valid for (in seconds)
/// </returns>
/// </summary>
public TimeSpan? MaxAge { get; private set; }

internal SocketGuildInvite(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, RestInviteMetadata rest) : base(_client, inviteCode)
{
Code = inviteCode;
Guild = guild;
Channel = channel;
CreatedAt = rest.CreatedAt;
Temporary = rest.IsTemporary;
MaxUses = rest.MaxUses;
Inviter = guild.GetUser(rest.Inviter.Id);
if (rest.MaxAge.HasValue)
MaxAge = TimeSpan.FromSeconds(rest.MaxAge.Value);
}
internal SocketGuildInvite(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, InviteUpdate Update) : base(_client, inviteCode)
{
Code = inviteCode;
Guild = guild;
Channel = channel;

if (Update.RawTimestamp.IsSpecified)
CreatedAt = Update.RawTimestamp.Value;
else
CreatedAt = DateTimeOffset.Now;

if (Update.inviter.IsSpecified)
Inviter = guild.GetUser(Update.inviter.Value.Id);

Temporary = Update.TempInvite;
MaxUses = Update.MaxUsers;
MaxAge = TimeSpan.FromSeconds(Update.RawAge);
}
internal static SocketGuildInvite Create(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, InviteUpdate Update)
{
var invite = new SocketGuildInvite(_client, guild, channel, inviteCode, Update);
return invite;
}
internal static SocketGuildInvite CreateFromRest(DiscordSocketClient _client, SocketGuild guild, SocketGuildChannel channel, string inviteCode, RestInviteMetadata rest)
{
var invite = new SocketGuildInvite(_client, guild, channel, inviteCode, rest);
return invite;
}
/// <summary>
/// Deletes the invite
/// </summary>
/// <param name="options"></param>
/// <returns></returns>
public Task DeleteAsync(RequestOptions options = null)
=> SocketInviteHelper.DeleteAsync(this, Discord, options);
}
}

+ 17
- 0
src/Discord.Net.WebSocket/Entities/Invites/SocketInviteHelper.cs View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Discord.WebSocket
{
internal class SocketInviteHelper
{
public static async Task DeleteAsync(ISocketInvite invite, BaseSocketClient client,
RequestOptions options)
{
await client.ApiClient.DeleteInviteAsync(invite.Code, options).ConfigureAwait(false);
}
}
}

Loading…
Cancel
Save