@@ -1,6 +1,5 @@ | |||||
using System.Collections.Concurrent; | using System.Collections.Concurrent; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Collections.Immutable; | |||||
using System.Linq; | using System.Linq; | ||||
namespace Discord.Commands | namespace Discord.Commands | ||||
@@ -49,7 +49,7 @@ namespace Discord.Audio | |||||
private uint _ssrc; | private uint _ssrc; | ||||
private byte[] _secretKey; | private byte[] _secretKey; | ||||
public CachedGuild Guild { get; } | |||||
public SocketGuild Guild { get; } | |||||
public DiscordVoiceAPIClient ApiClient { get; private set; } | public DiscordVoiceAPIClient ApiClient { get; private set; } | ||||
public ConnectionState ConnectionState { get; private set; } | public ConnectionState ConnectionState { get; private set; } | ||||
public int Latency { get; private set; } | public int Latency { get; private set; } | ||||
@@ -57,7 +57,7 @@ namespace Discord.Audio | |||||
private DiscordSocketClient Discord => Guild.Discord; | private DiscordSocketClient Discord => Guild.Discord; | ||||
/// <summary> Creates a new REST/WebSocket discord client. </summary> | /// <summary> Creates a new REST/WebSocket discord client. </summary> | ||||
public AudioClient(CachedGuild guild, int id) | |||||
public AudioClient(SocketGuild guild, int id) | |||||
{ | { | ||||
Guild = guild; | Guild = guild; | ||||
@@ -13,76 +13,76 @@ namespace Discord | |||||
private const double AverageUsersPerGuild = 47.78; //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 CollectionMultiplier = 1.05; //Add 5% buffer to handle growth | ||||
private readonly ConcurrentDictionary<ulong, ICachedChannel> _channels; | |||||
private readonly ConcurrentDictionary<ulong, CachedDMChannel> _dmChannels; | |||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds; | |||||
private readonly ConcurrentDictionary<ulong, CachedGlobalUser> _users; | |||||
private readonly ConcurrentDictionary<ulong, ISocketChannel> _channels; | |||||
private readonly ConcurrentDictionary<ulong, SocketDMChannel> _dmChannels; | |||||
private readonly ConcurrentDictionary<ulong, SocketGuild> _guilds; | |||||
private readonly ConcurrentDictionary<ulong, SocketGlobalUser> _users; | |||||
private readonly ConcurrentHashSet<ulong> _groupChannels; | private readonly ConcurrentHashSet<ulong> _groupChannels; | ||||
internal IReadOnlyCollection<ICachedChannel> Channels => _channels.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<CachedDMChannel> DMChannels => _dmChannels.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<CachedGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as CachedGroupChannel).ToReadOnlyCollection(_groupChannels); | |||||
internal IReadOnlyCollection<CachedGuild> Guilds => _guilds.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<CachedGlobalUser> Users => _users.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<ISocketChannel> Channels => _channels.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<SocketDMChannel> DMChannels => _dmChannels.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<SocketGroupChannel> GroupChannels => _groupChannels.Select(x => GetChannel(x) as SocketGroupChannel).ToReadOnlyCollection(_groupChannels); | |||||
internal IReadOnlyCollection<SocketGuild> Guilds => _guilds.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<SocketGlobalUser> Users => _users.ToReadOnlyCollection(); | |||||
internal IReadOnlyCollection<ICachedPrivateChannel> PrivateChannels => | |||||
_dmChannels.Select(x => x.Value as ICachedPrivateChannel).Concat( | |||||
_groupChannels.Select(x => GetChannel(x) as ICachedPrivateChannel)) | |||||
internal IReadOnlyCollection<ISocketPrivateChannel> PrivateChannels => | |||||
_dmChannels.Select(x => x.Value as ISocketPrivateChannel).Concat( | |||||
_groupChannels.Select(x => GetChannel(x) as ISocketPrivateChannel)) | |||||
.ToReadOnlyCollection(() => _dmChannels.Count + _groupChannels.Count); | .ToReadOnlyCollection(() => _dmChannels.Count + _groupChannels.Count); | ||||
public DataStore(int guildCount, int dmChannelCount) | public DataStore(int guildCount, int dmChannelCount) | ||||
{ | { | ||||
double estimatedChannelCount = guildCount * AverageChannelsPerGuild + dmChannelCount; | double estimatedChannelCount = guildCount * AverageChannelsPerGuild + dmChannelCount; | ||||
double estimatedUsersCount = guildCount * AverageUsersPerGuild; | double estimatedUsersCount = guildCount * AverageUsersPerGuild; | ||||
_channels = new ConcurrentDictionary<ulong, ICachedChannel>(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier)); | |||||
_dmChannels = new ConcurrentDictionary<ulong, CachedDMChannel>(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier)); | |||||
_guilds = new ConcurrentDictionary<ulong, CachedGuild>(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); | |||||
_users = new ConcurrentDictionary<ulong, CachedGlobalUser>(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); | |||||
_channels = new ConcurrentDictionary<ulong, ISocketChannel>(CollectionConcurrencyLevel, (int)(estimatedChannelCount * CollectionMultiplier)); | |||||
_dmChannels = new ConcurrentDictionary<ulong, SocketDMChannel>(CollectionConcurrencyLevel, (int)(dmChannelCount * CollectionMultiplier)); | |||||
_guilds = new ConcurrentDictionary<ulong, SocketGuild>(CollectionConcurrencyLevel, (int)(guildCount * CollectionMultiplier)); | |||||
_users = new ConcurrentDictionary<ulong, SocketGlobalUser>(CollectionConcurrencyLevel, (int)(estimatedUsersCount * CollectionMultiplier)); | |||||
_groupChannels = new ConcurrentHashSet<ulong>(CollectionConcurrencyLevel, (int)(10 * CollectionMultiplier)); | _groupChannels = new ConcurrentHashSet<ulong>(CollectionConcurrencyLevel, (int)(10 * CollectionMultiplier)); | ||||
} | } | ||||
internal ICachedChannel GetChannel(ulong id) | |||||
internal ISocketChannel GetChannel(ulong id) | |||||
{ | { | ||||
ICachedChannel channel; | |||||
ISocketChannel channel; | |||||
if (_channels.TryGetValue(id, out channel)) | if (_channels.TryGetValue(id, out channel)) | ||||
return channel; | return channel; | ||||
return null; | return null; | ||||
} | } | ||||
internal CachedDMChannel GetDMChannel(ulong userId) | |||||
internal SocketDMChannel GetDMChannel(ulong userId) | |||||
{ | { | ||||
CachedDMChannel channel; | |||||
SocketDMChannel channel; | |||||
if (_dmChannels.TryGetValue(userId, out channel)) | if (_dmChannels.TryGetValue(userId, out channel)) | ||||
return channel; | return channel; | ||||
return null; | return null; | ||||
} | } | ||||
internal void AddChannel(ICachedChannel channel) | |||||
internal void AddChannel(ISocketChannel channel) | |||||
{ | { | ||||
_channels[channel.Id] = channel; | _channels[channel.Id] = channel; | ||||
var dmChannel = channel as CachedDMChannel; | |||||
var dmChannel = channel as SocketDMChannel; | |||||
if (dmChannel != null) | if (dmChannel != null) | ||||
_dmChannels[dmChannel.Recipient.Id] = dmChannel; | _dmChannels[dmChannel.Recipient.Id] = dmChannel; | ||||
else | else | ||||
{ | { | ||||
var groupChannel = channel as CachedGroupChannel; | |||||
var groupChannel = channel as SocketGroupChannel; | |||||
if (groupChannel != null) | if (groupChannel != null) | ||||
_groupChannels.TryAdd(groupChannel.Id); | _groupChannels.TryAdd(groupChannel.Id); | ||||
} | } | ||||
} | } | ||||
internal ICachedChannel RemoveChannel(ulong id) | |||||
internal ISocketChannel RemoveChannel(ulong id) | |||||
{ | { | ||||
ICachedChannel channel; | |||||
ISocketChannel channel; | |||||
if (_channels.TryRemove(id, out channel)) | if (_channels.TryRemove(id, out channel)) | ||||
{ | { | ||||
var dmChannel = channel as CachedDMChannel; | |||||
var dmChannel = channel as SocketDMChannel; | |||||
if (dmChannel != null) | if (dmChannel != null) | ||||
{ | { | ||||
CachedDMChannel ignored; | |||||
SocketDMChannel ignored; | |||||
_dmChannels.TryRemove(dmChannel.Recipient.Id, out ignored); | _dmChannels.TryRemove(dmChannel.Recipient.Id, out ignored); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
var groupChannel = channel as CachedGroupChannel; | |||||
var groupChannel = channel as SocketGroupChannel; | |||||
if (groupChannel != null) | if (groupChannel != null) | ||||
_groupChannels.TryRemove(id); | _groupChannels.TryRemove(id); | ||||
} | } | ||||
@@ -91,39 +91,39 @@ namespace Discord | |||||
return null; | return null; | ||||
} | } | ||||
internal CachedGuild GetGuild(ulong id) | |||||
internal SocketGuild GetGuild(ulong id) | |||||
{ | { | ||||
CachedGuild guild; | |||||
SocketGuild guild; | |||||
if (_guilds.TryGetValue(id, out guild)) | if (_guilds.TryGetValue(id, out guild)) | ||||
return guild; | return guild; | ||||
return null; | return null; | ||||
} | } | ||||
internal void AddGuild(CachedGuild guild) | |||||
internal void AddGuild(SocketGuild guild) | |||||
{ | { | ||||
_guilds[guild.Id] = guild; | _guilds[guild.Id] = guild; | ||||
} | } | ||||
internal CachedGuild RemoveGuild(ulong id) | |||||
internal SocketGuild RemoveGuild(ulong id) | |||||
{ | { | ||||
CachedGuild guild; | |||||
SocketGuild guild; | |||||
if (_guilds.TryRemove(id, out guild)) | if (_guilds.TryRemove(id, out guild)) | ||||
return guild; | return guild; | ||||
return null; | return null; | ||||
} | } | ||||
internal CachedGlobalUser GetUser(ulong id) | |||||
internal SocketGlobalUser GetUser(ulong id) | |||||
{ | { | ||||
CachedGlobalUser user; | |||||
SocketGlobalUser user; | |||||
if (_users.TryGetValue(id, out user)) | if (_users.TryGetValue(id, out user)) | ||||
return user; | return user; | ||||
return null; | return null; | ||||
} | } | ||||
internal CachedGlobalUser GetOrAddUser(ulong id, Func<ulong, CachedGlobalUser> userFactory) | |||||
internal SocketGlobalUser GetOrAddUser(ulong id, Func<ulong, SocketGlobalUser> userFactory) | |||||
{ | { | ||||
return _users.GetOrAdd(id, userFactory); | return _users.GetOrAdd(id, userFactory); | ||||
} | } | ||||
internal CachedGlobalUser RemoveUser(ulong id) | |||||
internal SocketGlobalUser RemoveUser(ulong id) | |||||
{ | { | ||||
CachedGlobalUser user; | |||||
SocketGlobalUser user; | |||||
if (_users.TryRemove(id, out user)) | if (_users.TryRemove(id, out user)) | ||||
return user; | return user; | ||||
return null; | return null; | ||||
@@ -10,7 +10,6 @@ using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
using System.Collections.Concurrent; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
@@ -44,7 +44,7 @@ namespace Discord | |||||
/// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary> | /// <summary> Gets the estimated round-trip latency, in milliseconds, to the gateway server. </summary> | ||||
public int Latency { get; private set; } | public int Latency { get; private set; } | ||||
//From DiscordConfig | |||||
//From DiscordSocketConfig | |||||
internal int TotalShards { get; private set; } | internal int TotalShards { get; private set; } | ||||
internal int ConnectionTimeout { get; private set; } | internal int ConnectionTimeout { get; private set; } | ||||
internal int ReconnectDelay { get; private set; } | internal int ReconnectDelay { get; private set; } | ||||
@@ -55,8 +55,8 @@ namespace Discord | |||||
internal DataStore DataStore { get; private set; } | internal DataStore DataStore { get; private set; } | ||||
internal WebSocketProvider WebSocketProvider { get; private set; } | internal WebSocketProvider WebSocketProvider { get; private set; } | ||||
internal CachedSelfUser CurrentUser => _currentUser as CachedSelfUser; | |||||
internal IReadOnlyCollection<CachedGuild> Guilds => DataStore.Guilds; | |||||
internal SocketSelfUser CurrentUser => _currentUser as SocketSelfUser; | |||||
internal IReadOnlyCollection<SocketGuild> Guilds => DataStore.Guilds; | |||||
internal IReadOnlyCollection<VoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection(); | internal IReadOnlyCollection<VoiceRegion> VoiceRegions => _voiceRegions.ToReadOnlyCollection(); | ||||
/// <summary> Creates a new REST/WebSocket discord client. </summary> | /// <summary> Creates a new REST/WebSocket discord client. </summary> | ||||
@@ -340,15 +340,15 @@ namespace Discord | |||||
{ | { | ||||
return Task.FromResult<IReadOnlyCollection<IGuild>>(Guilds); | return Task.FromResult<IReadOnlyCollection<IGuild>>(Guilds); | ||||
} | } | ||||
internal CachedGuild AddGuild(ExtendedGuild model, DataStore dataStore) | |||||
internal SocketGuild AddGuild(ExtendedGuild model, DataStore dataStore) | |||||
{ | { | ||||
var guild = new CachedGuild(this, model, dataStore); | |||||
var guild = new SocketGuild(this, model, dataStore); | |||||
dataStore.AddGuild(guild); | dataStore.AddGuild(guild); | ||||
if (model.Large) | if (model.Large) | ||||
_largeGuilds.Enqueue(model.Id); | _largeGuilds.Enqueue(model.Id); | ||||
return guild; | return guild; | ||||
} | } | ||||
internal CachedGuild RemoveGuild(ulong id) | |||||
internal SocketGuild RemoveGuild(ulong id) | |||||
{ | { | ||||
var guild = DataStore.RemoveGuild(id); | var guild = DataStore.RemoveGuild(id); | ||||
foreach (var channel in guild.Channels) | foreach (var channel in guild.Channels) | ||||
@@ -367,7 +367,7 @@ namespace Discord | |||||
{ | { | ||||
return Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(DataStore.PrivateChannels); | return Task.FromResult<IReadOnlyCollection<IPrivateChannel>>(DataStore.PrivateChannels); | ||||
} | } | ||||
internal ICachedChannel AddPrivateChannel(API.Channel model, DataStore dataStore) | |||||
internal ISocketChannel AddPrivateChannel(API.Channel model, DataStore dataStore) | |||||
{ | { | ||||
switch (model.Type) | switch (model.Type) | ||||
{ | { | ||||
@@ -375,13 +375,13 @@ namespace Discord | |||||
{ | { | ||||
var recipients = model.Recipients.Value; | var recipients = model.Recipients.Value; | ||||
var user = GetOrAddUser(recipients[0], dataStore); | var user = GetOrAddUser(recipients[0], dataStore); | ||||
var channel = new CachedDMChannel(this, new CachedDMUser(user), model); | |||||
var channel = new SocketDMChannel(this, new SocketDMUser(user), model); | |||||
dataStore.AddChannel(channel); | dataStore.AddChannel(channel); | ||||
return channel; | return channel; | ||||
} | } | ||||
case ChannelType.Group: | case ChannelType.Group: | ||||
{ | { | ||||
var channel = new CachedGroupChannel(this, model); | |||||
var channel = new SocketGroupChannel(this, model); | |||||
channel.UpdateUsers(model.Recipients.Value, UpdateSource.Creation, dataStore); | channel.UpdateUsers(model.Recipients.Value, UpdateSource.Creation, dataStore); | ||||
dataStore.AddChannel(channel); | dataStore.AddChannel(channel); | ||||
return channel; | return channel; | ||||
@@ -390,9 +390,9 @@ namespace Discord | |||||
throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); | throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); | ||||
} | } | ||||
} | } | ||||
internal ICachedChannel RemovePrivateChannel(ulong id) | |||||
internal ISocketChannel RemovePrivateChannel(ulong id) | |||||
{ | { | ||||
var channel = DataStore.RemoveChannel(id) as ICachedPrivateChannel; | |||||
var channel = DataStore.RemoveChannel(id) as ISocketPrivateChannel; | |||||
foreach (var recipient in channel.Recipients) | foreach (var recipient in channel.Recipients) | ||||
recipient.User.RemoveRef(this); | recipient.User.RemoveRef(this); | ||||
return channel; | return channel; | ||||
@@ -413,13 +413,13 @@ namespace Discord | |||||
{ | { | ||||
return Task.FromResult<ISelfUser>(_currentUser); | return Task.FromResult<ISelfUser>(_currentUser); | ||||
} | } | ||||
internal CachedGlobalUser GetOrAddUser(API.User model, DataStore dataStore) | |||||
internal SocketGlobalUser GetOrAddUser(API.User model, DataStore dataStore) | |||||
{ | { | ||||
var user = dataStore.GetOrAddUser(model.Id, _ => new CachedGlobalUser(model)); | |||||
var user = dataStore.GetOrAddUser(model.Id, _ => new SocketGlobalUser(model)); | |||||
user.AddRef(); | user.AddRef(); | ||||
return user; | return user; | ||||
} | } | ||||
internal CachedGlobalUser RemoveUser(ulong id) | |||||
internal SocketGlobalUser RemoveUser(ulong id) | |||||
{ | { | ||||
return DataStore.RemoveUser(id); | return DataStore.RemoveUser(id); | ||||
} | } | ||||
@@ -429,10 +429,10 @@ namespace Discord | |||||
=> DownloadUsersAsync(DataStore.Guilds.Where(x => !x.HasAllMembers)); | => DownloadUsersAsync(DataStore.Guilds.Where(x => !x.HasAllMembers)); | ||||
/// <summary> Downloads the users list for the provided guilds, if they don't have a complete list. </summary> | /// <summary> Downloads the users list for the provided guilds, if they don't have a complete list. </summary> | ||||
public Task DownloadUsersAsync(IEnumerable<IGuild> guilds) | public Task DownloadUsersAsync(IEnumerable<IGuild> guilds) | ||||
=> DownloadUsersAsync(guilds.Select(x => x as CachedGuild).Where(x => x != null)); | |||||
=> DownloadUsersAsync(guilds.Select(x => x as SocketGuild).Where(x => x != null)); | |||||
public Task DownloadUsersAsync(params IGuild[] guilds) | public Task DownloadUsersAsync(params IGuild[] guilds) | ||||
=> DownloadUsersAsync(guilds.Select(x => x as CachedGuild).Where(x => x != null)); | |||||
private async Task DownloadUsersAsync(IEnumerable<CachedGuild> guilds) | |||||
=> DownloadUsersAsync(guilds.Select(x => x as SocketGuild).Where(x => x != null)); | |||||
private async Task DownloadUsersAsync(IEnumerable<SocketGuild> guilds) | |||||
{ | { | ||||
var cachedGuilds = guilds.ToArray(); | var cachedGuilds = guilds.ToArray(); | ||||
if (cachedGuilds.Length == 0) return; | if (cachedGuilds.Length == 0) return; | ||||
@@ -559,7 +559,7 @@ namespace Discord | |||||
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer); | var data = (payload as JToken).ToObject<ReadyEvent>(_serializer); | ||||
var dataStore = new DataStore(data.Guilds.Length, data.PrivateChannels.Length); | var dataStore = new DataStore(data.Guilds.Length, data.PrivateChannels.Length); | ||||
var currentUser = new CachedSelfUser(this, data.User); | |||||
var currentUser = new SocketSelfUser(this, data.User); | |||||
int unavailableGuilds = 0; | int unavailableGuilds = 0; | ||||
for (int i = 0; i < data.Guilds.Length; i++) | for (int i = 0; i < data.Guilds.Length; i++) | ||||
{ | { | ||||
@@ -625,7 +625,7 @@ namespace Discord | |||||
} | } | ||||
await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); | await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false); | ||||
CachedGuild guild; | |||||
SocketGuild guild; | |||||
if (data.Unavailable != false) | if (data.Unavailable != false) | ||||
{ | { | ||||
guild = AddGuild(data, DataStore); | guild = AddGuild(data, DataStore); | ||||
@@ -751,7 +751,7 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer); | var data = (payload as JToken).ToObject<API.Channel>(_serializer); | ||||
ICachedChannel channel = null; | |||||
ISocketChannel channel = null; | |||||
if (data.GuildId.IsSpecified) | if (data.GuildId.IsSpecified) | ||||
{ | { | ||||
var guild = DataStore.GetGuild(data.GuildId.Value); | var guild = DataStore.GetGuild(data.GuildId.Value); | ||||
@@ -789,7 +789,7 @@ namespace Discord | |||||
var before = channel.Clone(); | var before = channel.Clone(); | ||||
channel.Update(data, UpdateSource.WebSocket); | channel.Update(data, UpdateSource.WebSocket); | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored CHANNEL_UPDATE, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored CHANNEL_UPDATE, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
@@ -808,7 +808,7 @@ namespace Discord | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false); | ||||
ICachedChannel channel = null; | |||||
ISocketChannel channel = null; | |||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer); | var data = (payload as JToken).ToObject<API.Channel>(_serializer); | ||||
if (data.GuildId.IsSpecified) | if (data.GuildId.IsSpecified) | ||||
{ | { | ||||
@@ -978,7 +978,7 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); | var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
var user = channel.AddUser(data.User, DataStore); | var user = channel.AddUser(data.User, DataStore); | ||||
@@ -996,7 +996,7 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); | var data = (payload as JToken).ToObject<RecipientEvent>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as CachedGroupChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as SocketGroupChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
var user = channel.RemoveUser(data.User.Id); | var user = channel.RemoveUser(data.User.Id); | ||||
@@ -1166,10 +1166,10 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<API.Message>(_serializer); | var data = (payload as JToken).ToObject<API.Message>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored MESSAGE_CREATE, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored MESSAGE_CREATE, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
@@ -1200,17 +1200,17 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<API.Message>(_serializer); | var data = (payload as JToken).ToObject<API.Message>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored MESSAGE_UPDATE, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored MESSAGE_UPDATE, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
} | } | ||||
IMessage before = null, after = null; | IMessage before = null, after = null; | ||||
CachedMessage cachedMsg = channel.GetMessage(data.Id); | |||||
SocketMessage cachedMsg = channel.GetMessage(data.Id); | |||||
if (cachedMsg != null) | if (cachedMsg != null) | ||||
{ | { | ||||
before = cachedMsg.Clone(); | before = cachedMsg.Clone(); | ||||
@@ -1239,10 +1239,10 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<API.Message>(_serializer); | var data = (payload as JToken).ToObject<API.Message>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
@@ -1266,10 +1266,10 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer); | var data = (payload as JToken).ToObject<MessageDeleteBulkEvent>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE_BULK, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored MESSAGE_DELETE_BULK, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
@@ -1341,10 +1341,10 @@ namespace Discord | |||||
await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false); | ||||
var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer); | var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer); | ||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel; | |||||
var channel = DataStore.GetChannel(data.ChannelId) as ISocketMessageChannel; | |||||
if (channel != null) | if (channel != null) | ||||
{ | { | ||||
if (!((channel as ICachedGuildChannel)?.Guild.IsSynced ?? true)) | |||||
if (!((channel as ISocketGuildChannel)?.Guild.IsSynced ?? true)) | |||||
{ | { | ||||
await _gatewayLogger.DebugAsync("Ignored TYPING_START, guild is not synced yet.").ConfigureAwait(false); | await _gatewayLogger.DebugAsync("Ignored TYPING_START, guild is not synced yet.").ConfigureAwait(false); | ||||
return; | return; | ||||
@@ -1385,7 +1385,7 @@ namespace Discord | |||||
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer); | var data = (payload as JToken).ToObject<API.VoiceState>(_serializer); | ||||
if (data.GuildId.HasValue) | if (data.GuildId.HasValue) | ||||
{ | { | ||||
ICachedUser user; | |||||
ISocketUser user; | |||||
VoiceState before, after; | VoiceState before, after; | ||||
if (data.GuildId != null) | if (data.GuildId != null) | ||||
{ | { | ||||
@@ -1418,7 +1418,7 @@ namespace Discord | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as CachedGroupChannel; | |||||
var groupChannel = DataStore.GetChannel(data.ChannelId.Value) as SocketGroupChannel; | |||||
if (groupChannel != null) | if (groupChannel != null) | ||||
{ | { | ||||
if (data.ChannelId != null) | if (data.ChannelId != null) | ||||
@@ -24,8 +24,7 @@ namespace Discord | |||||
/// <summary> Gets a collection of messages in this channel. </summary> | /// <summary> Gets a collection of messages in this channel. </summary> | ||||
Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); | Task<IReadOnlyCollection<IMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch); | ||||
/// <summary> Bulk deletes multiple messages. </summary> | /// <summary> Bulk deletes multiple messages. </summary> | ||||
Task DeleteMessagesAsync(IEnumerable<IMessage> messages); | |||||
Task DeleteMessagesAsync(IEnumerable<IMessage> messages); | |||||
/// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.</summary> | /// <summary> Broadcasts the "user is typing" message to all users in this channel, lasting 10 seconds.</summary> | ||||
Task TriggerTypingAsync(); | Task TriggerTypingAsync(); | ||||
@@ -6,7 +6,8 @@ | |||||
public abstract DiscordClient Discord { get; } | public abstract DiscordClient Discord { get; } | ||||
bool IEntity<T>.IsAttached => false; | |||||
internal virtual bool IsAttached => false; | |||||
bool IEntity<T>.IsAttached => IsAttached; | |||||
public Entity(T id) | public Entity(T id) | ||||
{ | { | ||||
@@ -6,6 +6,9 @@ namespace Discord | |||||
{ | { | ||||
internal class GroupUser : IGroupUser | internal class GroupUser : IGroupUser | ||||
{ | { | ||||
internal virtual bool IsAttached => false; | |||||
bool IEntity<ulong>.IsAttached => IsAttached; | |||||
public GroupChannel Channel { get; private set; } | public GroupChannel Channel { get; private set; } | ||||
public User User { get; private set; } | public User User { get; private set; } | ||||
@@ -14,7 +17,6 @@ namespace Discord | |||||
public DateTimeOffset CreatedAt => User.CreatedAt; | public DateTimeOffset CreatedAt => User.CreatedAt; | ||||
public string Discriminator => User.Discriminator; | public string Discriminator => User.Discriminator; | ||||
public ushort DiscriminatorValue => User.DiscriminatorValue; | public ushort DiscriminatorValue => User.DiscriminatorValue; | ||||
public bool IsAttached => User.IsAttached; | |||||
public bool IsBot => User.IsBot; | public bool IsBot => User.IsBot; | ||||
public string Username => User.Username; | public string Username => User.Username; | ||||
public string Mention => MentionUtils.Mention(this, false); | public string Mention => MentionUtils.Mention(this, false); | ||||
@@ -13,6 +13,9 @@ namespace Discord | |||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||||
internal class GuildUser : IGuildUser, ISnowflakeEntity | internal class GuildUser : IGuildUser, ISnowflakeEntity | ||||
{ | { | ||||
internal virtual bool IsAttached => false; | |||||
bool IEntity<ulong>.IsAttached => IsAttached; | |||||
private long? _joinedAtTicks; | private long? _joinedAtTicks; | ||||
public string Nickname { get; private set; } | public string Nickname { get; private set; } | ||||
@@ -27,7 +30,6 @@ namespace Discord | |||||
public DateTimeOffset CreatedAt => User.CreatedAt; | public DateTimeOffset CreatedAt => User.CreatedAt; | ||||
public string Discriminator => User.Discriminator; | public string Discriminator => User.Discriminator; | ||||
public ushort DiscriminatorValue => User.DiscriminatorValue; | public ushort DiscriminatorValue => User.DiscriminatorValue; | ||||
public bool IsAttached => User.IsAttached; | |||||
public bool IsBot => User.IsBot; | public bool IsBot => User.IsBot; | ||||
public string Mention => MentionUtils.Mention(this, Nickname != null); | public string Mention => MentionUtils.Mention(this, Nickname != null); | ||||
public string Username => User.Username; | public string Username => User.Username; | ||||
@@ -1,19 +0,0 @@ | |||||
using Model = Discord.API.Message; | |||||
namespace Discord | |||||
{ | |||||
internal class CachedMessage : Message | |||||
{ | |||||
bool IEntity<ulong>.IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | |||||
public new ICachedMessageChannel Channel => base.Channel as ICachedMessageChannel; | |||||
public CachedMessage(ICachedMessageChannel channel, IUser author, Model model) | |||||
: base(channel, author, model) | |||||
{ | |||||
} | |||||
public CachedMessage Clone() => MemberwiseClone() as CachedMessage; | |||||
} | |||||
} |
@@ -1,21 +0,0 @@ | |||||
using System; | |||||
using Model = Discord.API.User; | |||||
namespace Discord | |||||
{ | |||||
internal class CachedSelfUser : SelfUser, ICachedUser | |||||
{ | |||||
bool IEntity<ulong>.IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | |||||
CachedGlobalUser ICachedUser.User { get { throw new NotSupportedException(); } } | |||||
public CachedSelfUser(DiscordSocketClient discord, Model model) | |||||
: base(discord, model) | |||||
{ | |||||
} | |||||
public CachedSelfUser Clone() => MemberwiseClone() as CachedSelfUser; | |||||
ICachedUser ICachedUser.Clone() => Clone(); | |||||
} | |||||
} |
@@ -2,10 +2,10 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal interface ICachedChannel : IChannel, ICachedEntity<ulong> | |||||
internal interface ISocketChannel : IChannel | |||||
{ | { | ||||
void Update(Model model, UpdateSource source); | void Update(Model model, UpdateSource source); | ||||
ICachedChannel Clone(); | |||||
ISocketChannel Clone(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,7 @@ | |||||
namespace Discord | |||||
{ | |||||
internal interface ISocketGuildChannel : ISocketChannel, IGuildChannel | |||||
{ | |||||
new SocketGuild Guild { get; } | |||||
} | |||||
} |
@@ -0,0 +1,16 @@ | |||||
using System.Collections.Generic; | |||||
using MessageModel = Discord.API.Message; | |||||
namespace Discord | |||||
{ | |||||
internal interface ISocketMessageChannel : ISocketChannel, IMessageChannel | |||||
{ | |||||
IReadOnlyCollection<ISocketUser> Users { get; } | |||||
SocketMessage AddMessage(ISocketUser author, MessageModel model); | |||||
SocketMessage GetMessage(ulong id); | |||||
SocketMessage RemoveMessage(ulong id); | |||||
ISocketUser GetUser(ulong id, bool skipCheck = false); | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
using System.Collections.Generic; | |||||
namespace Discord | |||||
{ | |||||
internal interface ISocketPrivateChannel : ISocketChannel, IPrivateChannel | |||||
{ | |||||
new IReadOnlyCollection<ISocketUser> Recipients { get; } | |||||
} | |||||
} |
@@ -10,51 +10,51 @@ namespace Discord | |||||
{ | { | ||||
internal class MessageCache : MessageManager | internal class MessageCache : MessageManager | ||||
{ | { | ||||
private readonly ConcurrentDictionary<ulong, CachedMessage> _messages; | |||||
private readonly ConcurrentDictionary<ulong, SocketMessage> _messages; | |||||
private readonly ConcurrentQueue<ulong> _orderedMessages; | private readonly ConcurrentQueue<ulong> _orderedMessages; | ||||
private readonly int _size; | private readonly int _size; | ||||
public override IReadOnlyCollection<CachedMessage> Messages => _messages.ToReadOnlyCollection(); | |||||
public override IReadOnlyCollection<SocketMessage> Messages => _messages.ToReadOnlyCollection(); | |||||
public MessageCache(DiscordSocketClient discord, ICachedMessageChannel channel) | |||||
public MessageCache(DiscordSocketClient discord, ISocketMessageChannel channel) | |||||
: base(discord, channel) | : base(discord, channel) | ||||
{ | { | ||||
_size = discord.MessageCacheSize; | _size = discord.MessageCacheSize; | ||||
_messages = new ConcurrentDictionary<ulong, CachedMessage>(1, (int)(_size * 1.05)); | |||||
_messages = new ConcurrentDictionary<ulong, SocketMessage>(1, (int)(_size * 1.05)); | |||||
_orderedMessages = new ConcurrentQueue<ulong>(); | _orderedMessages = new ConcurrentQueue<ulong>(); | ||||
} | } | ||||
public override void Add(CachedMessage message) | |||||
public override void Add(SocketMessage message) | |||||
{ | { | ||||
if (_messages.TryAdd(message.Id, message)) | if (_messages.TryAdd(message.Id, message)) | ||||
{ | { | ||||
_orderedMessages.Enqueue(message.Id); | _orderedMessages.Enqueue(message.Id); | ||||
ulong msgId; | ulong msgId; | ||||
CachedMessage msg; | |||||
SocketMessage msg; | |||||
while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) | while (_orderedMessages.Count > _size && _orderedMessages.TryDequeue(out msgId)) | ||||
_messages.TryRemove(msgId, out msg); | _messages.TryRemove(msgId, out msg); | ||||
} | } | ||||
} | } | ||||
public override CachedMessage Remove(ulong id) | |||||
public override SocketMessage Remove(ulong id) | |||||
{ | { | ||||
CachedMessage msg; | |||||
SocketMessage msg; | |||||
_messages.TryRemove(id, out msg); | _messages.TryRemove(id, out msg); | ||||
return msg; | return msg; | ||||
} | } | ||||
public override CachedMessage Get(ulong id) | |||||
public override SocketMessage Get(ulong id) | |||||
{ | { | ||||
CachedMessage result; | |||||
SocketMessage result; | |||||
if (_messages.TryGetValue(id, out result)) | if (_messages.TryGetValue(id, out result)) | ||||
return result; | return result; | ||||
return null; | return null; | ||||
} | } | ||||
public override IImmutableList<CachedMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||||
public override IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||||
{ | { | ||||
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); | if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); | ||||
if (limit == 0) return ImmutableArray<CachedMessage>.Empty; | |||||
if (limit == 0) return ImmutableArray<SocketMessage>.Empty; | |||||
IEnumerable<ulong> cachedMessageIds; | IEnumerable<ulong> cachedMessageIds; | ||||
if (fromMessageId == null) | if (fromMessageId == null) | ||||
@@ -68,7 +68,7 @@ namespace Discord | |||||
.Take(limit) | .Take(limit) | ||||
.Select(x => | .Select(x => | ||||
{ | { | ||||
CachedMessage msg; | |||||
SocketMessage msg; | |||||
if (_messages.TryGetValue(x, out msg)) | if (_messages.TryGetValue(x, out msg)) | ||||
return msg; | return msg; | ||||
return null; | return null; | ||||
@@ -77,7 +77,7 @@ namespace Discord | |||||
.ToImmutableArray(); | .ToImmutableArray(); | ||||
} | } | ||||
public override async Task<CachedMessage> DownloadAsync(ulong id) | |||||
public override async Task<SocketMessage> DownloadAsync(ulong id) | |||||
{ | { | ||||
var msg = Get(id); | var msg = Get(id); | ||||
if (msg != null) | if (msg != null) |
@@ -10,36 +10,36 @@ namespace Discord | |||||
internal class MessageManager | internal class MessageManager | ||||
{ | { | ||||
private readonly DiscordSocketClient _discord; | private readonly DiscordSocketClient _discord; | ||||
private readonly ICachedMessageChannel _channel; | |||||
private readonly ISocketMessageChannel _channel; | |||||
public virtual IReadOnlyCollection<CachedMessage> Messages | |||||
=> ImmutableArray.Create<CachedMessage>(); | |||||
public virtual IReadOnlyCollection<SocketMessage> Messages | |||||
=> ImmutableArray.Create<SocketMessage>(); | |||||
public MessageManager(DiscordSocketClient discord, ICachedMessageChannel channel) | |||||
public MessageManager(DiscordSocketClient discord, ISocketMessageChannel channel) | |||||
{ | { | ||||
_discord = discord; | _discord = discord; | ||||
_channel = channel; | _channel = channel; | ||||
} | } | ||||
public virtual void Add(CachedMessage message) { } | |||||
public virtual CachedMessage Remove(ulong id) => null; | |||||
public virtual CachedMessage Get(ulong id) => null; | |||||
public virtual void Add(SocketMessage message) { } | |||||
public virtual SocketMessage Remove(ulong id) => null; | |||||
public virtual SocketMessage Get(ulong id) => null; | |||||
public virtual IImmutableList<CachedMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||||
=> ImmutableArray.Create<CachedMessage>(); | |||||
public virtual IImmutableList<SocketMessage> GetMany(ulong? fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch) | |||||
=> ImmutableArray.Create<SocketMessage>(); | |||||
public virtual async Task<CachedMessage> DownloadAsync(ulong id) | |||||
public virtual async Task<SocketMessage> DownloadAsync(ulong id) | |||||
{ | { | ||||
var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); | var model = await _discord.ApiClient.GetChannelMessageAsync(_channel.Id, id).ConfigureAwait(false); | ||||
if (model != null) | if (model != null) | ||||
return new CachedMessage(_channel, new User(model.Author.Value), model); | |||||
return new SocketMessage(_channel, new User(model.Author.Value), model); | |||||
return null; | return null; | ||||
} | } | ||||
public async Task<IReadOnlyCollection<CachedMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit) | |||||
public async Task<IReadOnlyCollection<SocketMessage>> DownloadAsync(ulong? fromId, Direction dir, int limit) | |||||
{ | { | ||||
//TODO: Test heavily, especially the ordering of messages | //TODO: Test heavily, especially the ordering of messages | ||||
if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); | if (limit < 0) throw new ArgumentOutOfRangeException(nameof(limit)); | ||||
if (limit == 0) return ImmutableArray<CachedMessage>.Empty; | |||||
if (limit == 0) return ImmutableArray<SocketMessage>.Empty; | |||||
var cachedMessages = GetMany(fromId, dir, limit); | var cachedMessages = GetMany(fromId, dir, limit); | ||||
if (cachedMessages.Count == limit) | if (cachedMessages.Count == limit) | ||||
@@ -61,7 +61,7 @@ namespace Discord | |||||
}; | }; | ||||
var downloadedMessages = await _discord.ApiClient.GetChannelMessagesAsync(_channel.Id, args).ConfigureAwait(false); | var downloadedMessages = await _discord.ApiClient.GetChannelMessagesAsync(_channel.Id, args).ConfigureAwait(false); | ||||
var guild = (_channel as ICachedGuildChannel)?.Guild; | |||||
var guild = (_channel as ISocketGuildChannel)?.Guild; | |||||
return cachedMessages.Concat(downloadedMessages.Select(x => | return cachedMessages.Concat(downloadedMessages.Select(x => | ||||
{ | { | ||||
IUser user = _channel.GetUser(x.Author.Value.Id, true); | IUser user = _channel.GetUser(x.Author.Value.Id, true); | ||||
@@ -73,7 +73,7 @@ namespace Discord | |||||
else | else | ||||
user = newUser; | user = newUser; | ||||
} | } | ||||
return new CachedMessage(_channel, user, x); | |||||
return new SocketMessage(_channel, user, x); | |||||
})).ToImmutableArray(); | })).ToImmutableArray(); | ||||
} | } | ||||
} | } |
@@ -6,18 +6,18 @@ using Model = Discord.API.Channel; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedDMChannel : DMChannel, IDMChannel, ICachedChannel, ICachedMessageChannel, ICachedPrivateChannel | |||||
internal class SocketDMChannel : DMChannel, IDMChannel, ISocketChannel, ISocketMessageChannel, ISocketPrivateChannel | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
private readonly MessageManager _messages; | private readonly MessageManager _messages; | ||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public new CachedDMUser Recipient => base.Recipient as CachedDMUser; | |||||
public IReadOnlyCollection<ICachedUser> Members => ImmutableArray.Create<ICachedUser>(Discord.CurrentUser, Recipient); | |||||
IReadOnlyCollection<ICachedUser> ICachedPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | |||||
public new SocketDMUser Recipient => base.Recipient as SocketDMUser; | |||||
public IReadOnlyCollection<ISocketUser> Users => ImmutableArray.Create<ISocketUser>(Discord.CurrentUser, Recipient); | |||||
IReadOnlyCollection<ISocketUser> ISocketPrivateChannel.Recipients => ImmutableArray.Create(Recipient); | |||||
public CachedDMChannel(DiscordSocketClient discord, CachedDMUser recipient, Model model) | |||||
public SocketDMChannel(DiscordSocketClient discord, SocketDMUser recipient, Model model) | |||||
: base(discord, recipient, model) | : base(discord, recipient, model) | ||||
{ | { | ||||
if (Discord.MessageCacheSize > 0) | if (Discord.MessageCacheSize > 0) | ||||
@@ -27,8 +27,8 @@ namespace Discord | |||||
} | } | ||||
public override Task<IUser> GetUserAsync(ulong id) => Task.FromResult<IUser>(GetUser(id)); | public override Task<IUser> GetUserAsync(ulong id) => Task.FromResult<IUser>(GetUser(id)); | ||||
public override Task<IReadOnlyCollection<IUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IUser>>(Members); | |||||
public ICachedUser GetUser(ulong id) | |||||
public override Task<IReadOnlyCollection<IUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IUser>>(Users); | |||||
public ISocketUser GetUser(ulong id) | |||||
{ | { | ||||
var currentUser = Discord.CurrentUser; | var currentUser = Discord.CurrentUser; | ||||
if (id == Recipient.Id) | if (id == Recipient.Id) | ||||
@@ -51,25 +51,25 @@ namespace Discord | |||||
{ | { | ||||
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | ||||
} | } | ||||
public CachedMessage AddMessage(ICachedUser author, MessageModel model) | |||||
public SocketMessage AddMessage(ISocketUser author, MessageModel model) | |||||
{ | { | ||||
var msg = new CachedMessage(this, author, model); | |||||
var msg = new SocketMessage(this, author, model); | |||||
_messages.Add(msg); | _messages.Add(msg); | ||||
return msg; | return msg; | ||||
} | } | ||||
public CachedMessage GetMessage(ulong id) | |||||
public SocketMessage GetMessage(ulong id) | |||||
{ | { | ||||
return _messages.Get(id); | return _messages.Get(id); | ||||
} | } | ||||
public CachedMessage RemoveMessage(ulong id) | |||||
public SocketMessage RemoveMessage(ulong id) | |||||
{ | { | ||||
return _messages.Remove(id); | return _messages.Remove(id); | ||||
} | } | ||||
public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; | |||||
public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel; | |||||
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | ||||
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id); | |||||
ICachedChannel ICachedChannel.Clone() => Clone(); | |||||
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id); | |||||
ISocketChannel ISocketChannel.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -11,19 +11,19 @@ using VoiceStateModel = Discord.API.VoiceState; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedGroupChannel : GroupChannel, IGroupChannel, ICachedChannel, ICachedMessageChannel, ICachedPrivateChannel | |||||
internal class SocketGroupChannel : GroupChannel, IGroupChannel, ISocketChannel, ISocketMessageChannel, ISocketPrivateChannel | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
private readonly MessageManager _messages; | private readonly MessageManager _messages; | ||||
private ConcurrentDictionary<ulong, VoiceState> _voiceStates; | private ConcurrentDictionary<ulong, VoiceState> _voiceStates; | ||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public IReadOnlyCollection<ICachedUser> Members | |||||
=> _users.Select(x => x.Value as ICachedUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1); | |||||
public new IReadOnlyCollection<ICachedUser> Recipients => _users.Select(x => x.Value as ICachedUser).ToReadOnlyCollection(_users); | |||||
public IReadOnlyCollection<ISocketUser> Users | |||||
=> _users.Select(x => x.Value as ISocketUser).Concat(ImmutableArray.Create(Discord.CurrentUser)).ToReadOnlyCollection(() => _users.Count + 1); | |||||
public new IReadOnlyCollection<ISocketUser> Recipients => _users.Select(x => x.Value as ISocketUser).ToReadOnlyCollection(_users); | |||||
public CachedGroupChannel(DiscordSocketClient discord, Model model) | |||||
public SocketGroupChannel(DiscordSocketClient discord, Model model) | |||||
: base(discord, model) | : base(discord, model) | ||||
{ | { | ||||
if (Discord.MessageCacheSize > 0) | if (Discord.MessageCacheSize > 0) | ||||
@@ -45,46 +45,46 @@ namespace Discord | |||||
for (int i = 0; i < models.Length; i++) | for (int i = 0; i < models.Length; i++) | ||||
{ | { | ||||
var globalUser = Discord.GetOrAddUser(models[i], dataStore); | var globalUser = Discord.GetOrAddUser(models[i], dataStore); | ||||
users[models[i].Id] = new CachedGroupUser(this, globalUser); | |||||
users[models[i].Id] = new SocketGroupUser(this, globalUser); | |||||
} | } | ||||
_users = users; | _users = users; | ||||
} | } | ||||
internal override void UpdateUsers(UserModel[] models, UpdateSource source) | internal override void UpdateUsers(UserModel[] models, UpdateSource source) | ||||
=> UpdateUsers(models, source, Discord.DataStore); | => UpdateUsers(models, source, Discord.DataStore); | ||||
public CachedGroupUser AddUser(UserModel model, DataStore dataStore) | |||||
public SocketGroupUser AddUser(UserModel model, DataStore dataStore) | |||||
{ | { | ||||
GroupUser user; | GroupUser user; | ||||
if (_users.TryGetValue(model.Id, out user)) | if (_users.TryGetValue(model.Id, out user)) | ||||
return user as CachedGroupUser; | |||||
return user as SocketGroupUser; | |||||
else | else | ||||
{ | { | ||||
var globalUser = Discord.GetOrAddUser(model, dataStore); | var globalUser = Discord.GetOrAddUser(model, dataStore); | ||||
var privateUser = new CachedGroupUser(this, globalUser); | |||||
var privateUser = new SocketGroupUser(this, globalUser); | |||||
_users[privateUser.Id] = privateUser; | _users[privateUser.Id] = privateUser; | ||||
return privateUser; | return privateUser; | ||||
} | } | ||||
} | } | ||||
public ICachedUser GetUser(ulong id) | |||||
public ISocketUser GetUser(ulong id) | |||||
{ | { | ||||
GroupUser user; | GroupUser user; | ||||
if (_users.TryGetValue(id, out user)) | if (_users.TryGetValue(id, out user)) | ||||
return user as CachedGroupUser; | |||||
return user as SocketGroupUser; | |||||
if (id == Discord.CurrentUser.Id) | if (id == Discord.CurrentUser.Id) | ||||
return Discord.CurrentUser; | return Discord.CurrentUser; | ||||
return null; | return null; | ||||
} | } | ||||
public CachedGroupUser RemoveUser(ulong id) | |||||
public SocketGroupUser RemoveUser(ulong id) | |||||
{ | { | ||||
GroupUser user; | GroupUser user; | ||||
if (_users.TryRemove(id, out user)) | if (_users.TryRemove(id, out user)) | ||||
return user as CachedGroupUser; | |||||
return user as SocketGroupUser; | |||||
return null; | return null; | ||||
} | } | ||||
public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) | public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) | ||||
{ | { | ||||
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel; | |||||
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as SocketVoiceChannel; | |||||
var voiceState = new VoiceState(voiceChannel, model); | var voiceState = new VoiceState(voiceChannel, model); | ||||
(voiceStates ?? _voiceStates)[model.UserId] = voiceState; | (voiceStates ?? _voiceStates)[model.UserId] = voiceState; | ||||
return voiceState; | return voiceState; | ||||
@@ -116,25 +116,25 @@ namespace Discord | |||||
{ | { | ||||
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | ||||
} | } | ||||
public CachedMessage AddMessage(ICachedUser author, MessageModel model) | |||||
public SocketMessage AddMessage(ISocketUser author, MessageModel model) | |||||
{ | { | ||||
var msg = new CachedMessage(this, author, model); | |||||
var msg = new SocketMessage(this, author, model); | |||||
_messages.Add(msg); | _messages.Add(msg); | ||||
return msg; | return msg; | ||||
} | } | ||||
public CachedMessage GetMessage(ulong id) | |||||
public SocketMessage GetMessage(ulong id) | |||||
{ | { | ||||
return _messages.Get(id); | return _messages.Get(id); | ||||
} | } | ||||
public CachedMessage RemoveMessage(ulong id) | |||||
public SocketMessage RemoveMessage(ulong id) | |||||
{ | { | ||||
return _messages.Remove(id); | return _messages.Remove(id); | ||||
} | } | ||||
public CachedDMChannel Clone() => MemberwiseClone() as CachedDMChannel; | |||||
public SocketDMChannel Clone() => MemberwiseClone() as SocketDMChannel; | |||||
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | ||||
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id); | |||||
ICachedChannel ICachedChannel.Clone() => Clone(); | |||||
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id); | |||||
ISocketChannel ISocketChannel.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -7,19 +7,19 @@ using Model = Discord.API.Channel; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedTextChannel : TextChannel, ICachedGuildChannel, ICachedMessageChannel | |||||
internal class SocketTextChannel : TextChannel, ISocketGuildChannel, ISocketMessageChannel | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
private readonly MessageManager _messages; | private readonly MessageManager _messages; | ||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public new CachedGuild Guild => base.Guild as CachedGuild; | |||||
public new SocketGuild Guild => base.Guild as SocketGuild; | |||||
public IReadOnlyCollection<CachedGuildUser> Members | |||||
public IReadOnlyCollection<SocketGuildUser> Members | |||||
=> Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray(); | => Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray(); | ||||
public CachedTextChannel(CachedGuild guild, Model model) | |||||
public SocketTextChannel(SocketGuild guild, Model model) | |||||
: base(guild, model) | : base(guild, model) | ||||
{ | { | ||||
if (Discord.MessageCacheSize > 0) | if (Discord.MessageCacheSize > 0) | ||||
@@ -30,7 +30,7 @@ namespace Discord | |||||
public override Task<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id)); | public override Task<IGuildUser> GetUserAsync(ulong id) => Task.FromResult<IGuildUser>(GetUser(id)); | ||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | ||||
public CachedGuildUser GetUser(ulong id, bool skipCheck = false) | |||||
public SocketGuildUser GetUser(ulong id, bool skipCheck = false) | |||||
{ | { | ||||
var user = Guild.GetUser(id); | var user = Guild.GetUser(id); | ||||
if (skipCheck) return user; | if (skipCheck) return user; | ||||
@@ -57,27 +57,27 @@ namespace Discord | |||||
return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | return await _messages.DownloadAsync(fromMessageId, dir, limit).ConfigureAwait(false); | ||||
} | } | ||||
public CachedMessage AddMessage(ICachedUser author, MessageModel model) | |||||
public SocketMessage AddMessage(ISocketUser author, MessageModel model) | |||||
{ | { | ||||
var msg = new CachedMessage(this, author, model); | |||||
var msg = new SocketMessage(this, author, model); | |||||
_messages.Add(msg); | _messages.Add(msg); | ||||
return msg; | return msg; | ||||
} | } | ||||
public CachedMessage GetMessage(ulong id) | |||||
public SocketMessage GetMessage(ulong id) | |||||
{ | { | ||||
return _messages.Get(id); | return _messages.Get(id); | ||||
} | } | ||||
public CachedMessage RemoveMessage(ulong id) | |||||
public SocketMessage RemoveMessage(ulong id) | |||||
{ | { | ||||
return _messages.Remove(id); | return _messages.Remove(id); | ||||
} | } | ||||
public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel; | |||||
public SocketTextChannel Clone() => MemberwiseClone() as SocketTextChannel; | |||||
IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members; | |||||
IReadOnlyCollection<ISocketUser> ISocketMessageChannel.Users => Members; | |||||
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | IMessage IMessageChannel.GetCachedMessage(ulong id) => GetMessage(id); | ||||
ICachedUser ICachedMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id, skipCheck); | |||||
ICachedChannel ICachedChannel.Clone() => Clone(); | |||||
ISocketUser ISocketMessageChannel.GetUser(ulong id, bool skipCheck) => GetUser(id, skipCheck); | |||||
ISocketChannel ISocketChannel.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -8,17 +8,17 @@ using Model = Discord.API.Channel; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedVoiceChannel : VoiceChannel, ICachedGuildChannel | |||||
internal class SocketVoiceChannel : VoiceChannel, ISocketGuildChannel | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public new CachedGuild Guild => base.Guild as CachedGuild; | |||||
public new SocketGuild Guild => base.Guild as SocketGuild; | |||||
public IReadOnlyCollection<IGuildUser> Members | public IReadOnlyCollection<IGuildUser> Members | ||||
=> Guild.VoiceStates.Where(x => x.Value.VoiceChannel.Id == Id).Select(x => Guild.GetUser(x.Key)).ToImmutableArray(); | => Guild.VoiceStates.Where(x => x.Value.VoiceChannel.Id == Id).Select(x => Guild.GetUser(x.Key)).ToImmutableArray(); | ||||
public CachedVoiceChannel(CachedGuild guild, Model model) | |||||
public SocketVoiceChannel(SocketGuild guild, Model model) | |||||
: base(guild, model) | : base(guild, model) | ||||
{ | { | ||||
} | } | ||||
@@ -48,8 +48,8 @@ namespace Discord | |||||
//TODO: Block and return | //TODO: Block and return | ||||
} | } | ||||
public CachedVoiceChannel Clone() => MemberwiseClone() as CachedVoiceChannel; | |||||
public SocketVoiceChannel Clone() => MemberwiseClone() as SocketVoiceChannel; | |||||
ICachedChannel ICachedChannel.Clone() => Clone(); | |||||
ISocketChannel ISocketChannel.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -19,14 +19,14 @@ using VoiceStateModel = Discord.API.VoiceState; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedGuild : Guild, IGuild, IUserGuild | |||||
internal class SocketGuild : Guild, IGuild, IUserGuild | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
private readonly SemaphoreSlim _audioLock; | private readonly SemaphoreSlim _audioLock; | ||||
private TaskCompletionSource<bool> _syncPromise, _downloaderPromise; | private TaskCompletionSource<bool> _syncPromise, _downloaderPromise; | ||||
private ConcurrentHashSet<ulong> _channels; | private ConcurrentHashSet<ulong> _channels; | ||||
private ConcurrentDictionary<ulong, CachedGuildUser> _members; | |||||
private ConcurrentDictionary<ulong, SocketGuildUser> _members; | |||||
private ConcurrentDictionary<ulong, VoiceState> _voiceStates; | private ConcurrentDictionary<ulong, VoiceState> _voiceStates; | ||||
internal bool _available; | internal bool _available; | ||||
@@ -41,20 +41,20 @@ namespace Discord | |||||
public Task DownloaderPromise => _downloaderPromise.Task; | public Task DownloaderPromise => _downloaderPromise.Task; | ||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public CachedGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id); | |||||
public IReadOnlyCollection<ICachedGuildChannel> Channels | |||||
public SocketGuildUser CurrentUser => GetUser(Discord.CurrentUser.Id); | |||||
public IReadOnlyCollection<ISocketGuildChannel> Channels | |||||
{ | { | ||||
get | get | ||||
{ | { | ||||
var channels = _channels; | var channels = _channels; | ||||
var store = Discord.DataStore; | var store = Discord.DataStore; | ||||
return channels.Select(x => store.GetChannel(x) as ICachedGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels); | |||||
return channels.Select(x => store.GetChannel(x) as ISocketGuildChannel).Where(x => x != null).ToReadOnlyCollection(channels); | |||||
} | } | ||||
} | } | ||||
public IReadOnlyCollection<CachedGuildUser> Members => _members.ToReadOnlyCollection(); | |||||
public IReadOnlyCollection<SocketGuildUser> Members => _members.ToReadOnlyCollection(); | |||||
public IEnumerable<KeyValuePair<ulong, VoiceState>> VoiceStates => _voiceStates; | public IEnumerable<KeyValuePair<ulong, VoiceState>> VoiceStates => _voiceStates; | ||||
public CachedGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model) | |||||
public SocketGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model) | |||||
{ | { | ||||
_audioLock = new SemaphoreSlim(1, 1); | _audioLock = new SemaphoreSlim(1, 1); | ||||
_syncPromise = new TaskCompletionSource<bool>(); | _syncPromise = new TaskCompletionSource<bool>(); | ||||
@@ -72,7 +72,7 @@ namespace Discord | |||||
if (_channels == null) | if (_channels == null) | ||||
_channels = new ConcurrentHashSet<ulong>(); | _channels = new ConcurrentHashSet<ulong>(); | ||||
if (_members == null) | if (_members == null) | ||||
_members = new ConcurrentDictionary<ulong, CachedGuildUser>(); | |||||
_members = new ConcurrentDictionary<ulong, SocketGuildUser>(); | |||||
if (_roles == null) | if (_roles == null) | ||||
_roles = new ConcurrentDictionary<ulong, Role>(); | _roles = new ConcurrentDictionary<ulong, Role>(); | ||||
if (Emojis == null) | if (Emojis == null) | ||||
@@ -93,7 +93,7 @@ namespace Discord | |||||
} | } | ||||
_channels = channels; | _channels = channels; | ||||
var members = new ConcurrentDictionary<ulong, CachedGuildUser>(1, (int)(model.Presences.Length * 1.05)); | |||||
var members = new ConcurrentDictionary<ulong, SocketGuildUser>(1, (int)(model.Presences.Length * 1.05)); | |||||
{ | { | ||||
DownloadedMemberCount = 0; | DownloadedMemberCount = 0; | ||||
for (int i = 0; i < model.Members.Length; i++) | for (int i = 0; i < model.Members.Length; i++) | ||||
@@ -121,7 +121,7 @@ namespace Discord | |||||
{ | { | ||||
if (source == UpdateSource.Rest && IsAttached) return; | if (source == UpdateSource.Rest && IsAttached) return; | ||||
var members = new ConcurrentDictionary<ulong, CachedGuildUser>(1, (int)(model.Presences.Length * 1.05)); | |||||
var members = new ConcurrentDictionary<ulong, SocketGuildUser>(1, (int)(model.Presences.Length * 1.05)); | |||||
{ | { | ||||
DownloadedMemberCount = 0; | DownloadedMemberCount = 0; | ||||
for (int i = 0; i < model.Members.Length; i++) | for (int i = 0; i < model.Members.Length; i++) | ||||
@@ -154,14 +154,14 @@ namespace Discord | |||||
(channels ?? _channels).TryAdd(model.Id); | (channels ?? _channels).TryAdd(model.Id); | ||||
dataStore.AddChannel(channel); | dataStore.AddChannel(channel); | ||||
} | } | ||||
public ICachedGuildChannel GetChannel(ulong id) | |||||
public ISocketGuildChannel GetChannel(ulong id) | |||||
{ | { | ||||
return Discord.DataStore.GetChannel(id) as ICachedGuildChannel; | |||||
return Discord.DataStore.GetChannel(id) as ISocketGuildChannel; | |||||
} | } | ||||
public ICachedGuildChannel RemoveChannel(ulong id) | |||||
public ISocketGuildChannel RemoveChannel(ulong id) | |||||
{ | { | ||||
_channels.TryRemove(id); | _channels.TryRemove(id); | ||||
return Discord.DataStore.RemoveChannel(id) as ICachedGuildChannel; | |||||
return Discord.DataStore.RemoveChannel(id) as ISocketGuildChannel; | |||||
} | } | ||||
public Role AddRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null) | public Role AddRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null) | ||||
@@ -183,48 +183,48 @@ namespace Discord | |||||
=> Task.FromResult<IGuildUser>(CurrentUser); | => Task.FromResult<IGuildUser>(CurrentUser); | ||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() | public override Task<IReadOnlyCollection<IGuildUser>> GetUsersAsync() | ||||
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members); | ||||
public CachedGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null) | |||||
public SocketGuildUser AddUser(MemberModel model, DataStore dataStore, ConcurrentDictionary<ulong, SocketGuildUser> members = null) | |||||
{ | { | ||||
members = members ?? _members; | members = members ?? _members; | ||||
CachedGuildUser member; | |||||
SocketGuildUser member; | |||||
if (members.TryGetValue(model.User.Id, out member)) | if (members.TryGetValue(model.User.Id, out member)) | ||||
member.Update(model, UpdateSource.WebSocket); | member.Update(model, UpdateSource.WebSocket); | ||||
else | else | ||||
{ | { | ||||
var user = Discord.GetOrAddUser(model.User, dataStore); | var user = Discord.GetOrAddUser(model.User, dataStore); | ||||
member = new CachedGuildUser(this, user, model); | |||||
member = new SocketGuildUser(this, user, model); | |||||
members[user.Id] = member; | members[user.Id] = member; | ||||
DownloadedMemberCount++; | DownloadedMemberCount++; | ||||
} | } | ||||
return member; | return member; | ||||
} | } | ||||
public CachedGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary<ulong, CachedGuildUser> members = null) | |||||
public SocketGuildUser AddOrUpdateUser(PresenceModel model, DataStore dataStore, ConcurrentDictionary<ulong, SocketGuildUser> members = null) | |||||
{ | { | ||||
members = members ?? _members; | members = members ?? _members; | ||||
CachedGuildUser member; | |||||
SocketGuildUser member; | |||||
if (members.TryGetValue(model.User.Id, out member)) | if (members.TryGetValue(model.User.Id, out member)) | ||||
member.Update(model, UpdateSource.WebSocket); | member.Update(model, UpdateSource.WebSocket); | ||||
else | else | ||||
{ | { | ||||
var user = Discord.GetOrAddUser(model.User, dataStore); | var user = Discord.GetOrAddUser(model.User, dataStore); | ||||
member = new CachedGuildUser(this, user, model); | |||||
member = new SocketGuildUser(this, user, model); | |||||
members[user.Id] = member; | members[user.Id] = member; | ||||
DownloadedMemberCount++; | DownloadedMemberCount++; | ||||
} | } | ||||
return member; | return member; | ||||
} | } | ||||
public CachedGuildUser GetUser(ulong id) | |||||
public SocketGuildUser GetUser(ulong id) | |||||
{ | { | ||||
CachedGuildUser member; | |||||
SocketGuildUser member; | |||||
if (_members.TryGetValue(id, out member)) | if (_members.TryGetValue(id, out member)) | ||||
return member; | return member; | ||||
return null; | return null; | ||||
} | } | ||||
public CachedGuildUser RemoveUser(ulong id) | |||||
public SocketGuildUser RemoveUser(ulong id) | |||||
{ | { | ||||
CachedGuildUser member; | |||||
SocketGuildUser member; | |||||
if (_members.TryRemove(id, out member)) | if (_members.TryRemove(id, out member)) | ||||
return member; | return member; | ||||
return null; | return null; | ||||
@@ -240,7 +240,7 @@ namespace Discord | |||||
public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) | public VoiceState AddOrUpdateVoiceState(VoiceStateModel model, DataStore dataStore, ConcurrentDictionary<ulong, VoiceState> voiceStates = null) | ||||
{ | { | ||||
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as CachedVoiceChannel; | |||||
var voiceChannel = dataStore.GetChannel(model.ChannelId.Value) as SocketVoiceChannel; | |||||
var voiceState = new VoiceState(voiceChannel, model); | var voiceState = new VoiceState(voiceChannel, model); | ||||
(voiceStates ?? _voiceStates)[model.UserId] = voiceState; | (voiceStates ?? _voiceStates)[model.UserId] = voiceState; | ||||
return voiceState; | return voiceState; | ||||
@@ -309,16 +309,16 @@ namespace Discord | |||||
await audioClient.ConnectAsync(url, CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); | await audioClient.ConnectAsync(url, CurrentUser.Id, voiceState.VoiceSessionId, token).ConfigureAwait(false); | ||||
} | } | ||||
public CachedGuild Clone() => MemberwiseClone() as CachedGuild; | |||||
public SocketGuild Clone() => MemberwiseClone() as SocketGuild; | |||||
new internal ICachedGuildChannel ToChannel(ChannelModel model) | |||||
new internal ISocketGuildChannel ToChannel(ChannelModel model) | |||||
{ | { | ||||
switch (model.Type) | switch (model.Type) | ||||
{ | { | ||||
case ChannelType.Text: | case ChannelType.Text: | ||||
return new CachedTextChannel(this, model); | |||||
return new SocketTextChannel(this, model); | |||||
case ChannelType.Voice: | case ChannelType.Voice: | ||||
return new CachedVoiceChannel(this, model); | |||||
return new SocketVoiceChannel(this, model); | |||||
default: | default: | ||||
throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); | throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); | ||||
} | } |
@@ -1,7 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
internal interface ICachedGuildChannel : ICachedChannel, IGuildChannel | |||||
{ | |||||
new CachedGuild Guild { get; } | |||||
} | |||||
} |
@@ -1,16 +0,0 @@ | |||||
using System.Collections.Generic; | |||||
using MessageModel = Discord.API.Message; | |||||
namespace Discord | |||||
{ | |||||
internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel | |||||
{ | |||||
IReadOnlyCollection<ICachedUser> Members { get; } | |||||
CachedMessage AddMessage(ICachedUser author, MessageModel model); | |||||
CachedMessage GetMessage(ulong id); | |||||
CachedMessage RemoveMessage(ulong id); | |||||
ICachedUser GetUser(ulong id, bool skipCheck = false); | |||||
} | |||||
} |
@@ -1,9 +0,0 @@ | |||||
using System.Collections.Generic; | |||||
namespace Discord | |||||
{ | |||||
internal interface ICachedPrivateChannel : ICachedChannel, IPrivateChannel | |||||
{ | |||||
new IReadOnlyCollection<ICachedUser> Recipients { get; } | |||||
} | |||||
} |
@@ -1,9 +0,0 @@ | |||||
namespace Discord | |||||
{ | |||||
internal interface ICachedUser : IUser, ICachedEntity<ulong> | |||||
{ | |||||
CachedGlobalUser User { get; } | |||||
ICachedUser Clone(); | |||||
} | |||||
} |
@@ -0,0 +1,19 @@ | |||||
using Model = Discord.API.Message; | |||||
namespace Discord | |||||
{ | |||||
internal class SocketMessage : Message | |||||
{ | |||||
internal override bool IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | |||||
public new ISocketMessageChannel Channel => base.Channel as ISocketMessageChannel; | |||||
public SocketMessage(ISocketMessageChannel channel, IUser author, Model model) | |||||
: base(channel, author, model) | |||||
{ | |||||
} | |||||
public SocketMessage Clone() => MemberwiseClone() as SocketMessage; | |||||
} | |||||
} |
@@ -0,0 +1,9 @@ | |||||
namespace Discord | |||||
{ | |||||
internal interface ISocketUser : IUser, IEntity<ulong> | |||||
{ | |||||
SocketGlobalUser User { get; } | |||||
ISocketUser Clone(); | |||||
} | |||||
} |
@@ -5,11 +5,12 @@ using PresenceModel = Discord.API.Presence; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||||
internal class CachedDMUser : ICachedUser | |||||
internal class SocketDMUser : ISocketUser | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal bool IsAttached => true; | |||||
bool IEntity<ulong>.IsAttached => IsAttached; | |||||
public CachedGlobalUser User { get; } | |||||
public SocketGlobalUser User { get; } | |||||
public DiscordSocketClient Discord => User.Discord; | public DiscordSocketClient Discord => User.Discord; | ||||
@@ -22,12 +23,11 @@ namespace Discord | |||||
public DateTimeOffset CreatedAt => User.CreatedAt; | public DateTimeOffset CreatedAt => User.CreatedAt; | ||||
public string Discriminator => User.Discriminator; | public string Discriminator => User.Discriminator; | ||||
public ushort DiscriminatorValue => User.DiscriminatorValue; | public ushort DiscriminatorValue => User.DiscriminatorValue; | ||||
public bool IsAttached => User.IsAttached; | |||||
public bool IsBot => User.IsBot; | public bool IsBot => User.IsBot; | ||||
public string Mention => MentionUtils.Mention(this); | public string Mention => MentionUtils.Mention(this); | ||||
public string Username => User.Username; | public string Username => User.Username; | ||||
public CachedDMUser(CachedGlobalUser user) | |||||
public SocketDMUser(SocketGlobalUser user) | |||||
{ | { | ||||
User = user; | User = user; | ||||
} | } | ||||
@@ -37,8 +37,8 @@ namespace Discord | |||||
User.Update(model, source); | User.Update(model, source); | ||||
} | } | ||||
public CachedDMUser Clone() => MemberwiseClone() as CachedDMUser; | |||||
ICachedUser ICachedUser.Clone() => Clone(); | |||||
public SocketDMUser Clone() => MemberwiseClone() as SocketDMUser; | |||||
ISocketUser ISocketUser.Clone() => Clone(); | |||||
public override string ToString() => $"{Username}#{Discriminator}"; | public override string ToString() => $"{Username}#{Discriminator}"; | ||||
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; | private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; |
@@ -4,18 +4,18 @@ using PresenceModel = Discord.API.Presence; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedGlobalUser : User, ICachedUser | |||||
internal class SocketGlobalUser : User, ISocketUser | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
private ushort _references; | private ushort _references; | ||||
public Presence Presence { get; private set; } | public Presence Presence { get; private set; } | ||||
public new DiscordSocketClient Discord { get { throw new NotSupportedException(); } } | public new DiscordSocketClient Discord { get { throw new NotSupportedException(); } } | ||||
CachedGlobalUser ICachedUser.User => this; | |||||
SocketGlobalUser ISocketUser.User => this; | |||||
public CachedGlobalUser(Model model) | |||||
public SocketGlobalUser(Model model) | |||||
: base(model) | : base(model) | ||||
{ | { | ||||
} | } | ||||
@@ -53,7 +53,7 @@ namespace Discord | |||||
//} | //} | ||||
} | } | ||||
public CachedGlobalUser Clone() => MemberwiseClone() as CachedGlobalUser; | |||||
ICachedUser ICachedUser.Clone() => Clone(); | |||||
public SocketGlobalUser Clone() => MemberwiseClone() as SocketGlobalUser; | |||||
ISocketUser ISocketUser.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -3,13 +3,13 @@ | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
[DebuggerDisplay("{DebuggerDisplay,nq}")] | [DebuggerDisplay("{DebuggerDisplay,nq}")] | ||||
internal class CachedGroupUser : GroupUser, ICachedUser | |||||
internal class SocketGroupUser : GroupUser, ISocketUser | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public new CachedGroupChannel Channel => base.Channel as CachedGroupChannel; | |||||
public new CachedGlobalUser User => base.User as CachedGlobalUser; | |||||
public new SocketGroupChannel Channel => base.Channel as SocketGroupChannel; | |||||
public new SocketGlobalUser User => base.User as SocketGlobalUser; | |||||
public Presence Presence => User.Presence; //{ get; private set; } | public Presence Presence => User.Presence; //{ get; private set; } | ||||
public override Game Game => Presence.Game; | public override Game Game => Presence.Game; | ||||
@@ -19,15 +19,15 @@ namespace Discord | |||||
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; | public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; | ||||
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; | public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; | ||||
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; | public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; | ||||
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; | |||||
public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; | |||||
public CachedGroupUser(CachedGroupChannel channel, CachedGlobalUser user) | |||||
public SocketGroupUser(SocketGroupChannel channel, SocketGlobalUser user) | |||||
: base(channel, user) | : base(channel, user) | ||||
{ | { | ||||
} | } | ||||
public CachedGroupUser Clone() => MemberwiseClone() as CachedGroupUser; | |||||
ICachedUser ICachedUser.Clone() => Clone(); | |||||
public SocketGroupUser Clone() => MemberwiseClone() as SocketGroupUser; | |||||
ISocketUser ISocketUser.Clone() => Clone(); | |||||
public override string ToString() => $"{Username}#{Discriminator}"; | public override string ToString() => $"{Username}#{Discriminator}"; | ||||
private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; | private string DebuggerDisplay => $"{Username}#{Discriminator} ({Id})"; |
@@ -3,13 +3,13 @@ using PresenceModel = Discord.API.Presence; | |||||
namespace Discord | namespace Discord | ||||
{ | { | ||||
internal class CachedGuildUser : GuildUser, ICachedUser | |||||
internal class SocketGuildUser : GuildUser, ISocketUser | |||||
{ | { | ||||
bool IEntity<ulong>.IsAttached => true; | |||||
internal override bool IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | ||||
public new CachedGuild Guild => base.Guild as CachedGuild; | |||||
public new CachedGlobalUser User => base.User as CachedGlobalUser; | |||||
public new SocketGuild Guild => base.Guild as SocketGuild; | |||||
public new SocketGlobalUser User => base.User as SocketGlobalUser; | |||||
public Presence Presence => User.Presence; //{ get; private set; } | public Presence Presence => User.Presence; //{ get; private set; } | ||||
public override Game Game => Presence.Game; | public override Game Game => Presence.Game; | ||||
@@ -19,14 +19,14 @@ namespace Discord | |||||
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; | public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false; | ||||
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; | public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false; | ||||
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; | public bool IsSuppressed => VoiceState?.IsSuppressed ?? false; | ||||
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; | |||||
public SocketVoiceChannel VoiceChannel => VoiceState?.VoiceChannel; | |||||
public CachedGuildUser(CachedGuild guild, CachedGlobalUser user, Model model) | |||||
public SocketGuildUser(SocketGuild guild, SocketGlobalUser user, Model model) | |||||
: base(guild, user, model) | : base(guild, user, model) | ||||
{ | { | ||||
//Presence = new Presence(null, UserStatus.Offline); | //Presence = new Presence(null, UserStatus.Offline); | ||||
} | } | ||||
public CachedGuildUser(CachedGuild guild, CachedGlobalUser user, PresenceModel model) | |||||
public SocketGuildUser(SocketGuild guild, SocketGlobalUser user, PresenceModel model) | |||||
: base(guild, user, model) | : base(guild, user, model) | ||||
{ | { | ||||
} | } | ||||
@@ -41,7 +41,7 @@ namespace Discord | |||||
User.Update(model, source); | User.Update(model, source); | ||||
} | } | ||||
public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser; | |||||
ICachedUser ICachedUser.Clone() => Clone(); | |||||
public SocketGuildUser Clone() => MemberwiseClone() as SocketGuildUser; | |||||
ISocketUser ISocketUser.Clone() => Clone(); | |||||
} | } | ||||
} | } |
@@ -0,0 +1,21 @@ | |||||
using System; | |||||
using Model = Discord.API.User; | |||||
namespace Discord | |||||
{ | |||||
internal class SocketSelfUser : SelfUser, ISocketUser | |||||
{ | |||||
internal override bool IsAttached => true; | |||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient; | |||||
SocketGlobalUser ISocketUser.User { get { throw new NotSupportedException(); } } | |||||
public SocketSelfUser(DiscordSocketClient discord, Model model) | |||||
: base(discord, model) | |||||
{ | |||||
} | |||||
public SocketSelfUser Clone() => MemberwiseClone() as SocketSelfUser; | |||||
ISocketUser ISocketUser.Clone() => Clone(); | |||||
} | |||||
} |
@@ -19,7 +19,7 @@ namespace Discord | |||||
private readonly Flags _voiceStates; | private readonly Flags _voiceStates; | ||||
public CachedVoiceChannel VoiceChannel { get; } | |||||
public SocketVoiceChannel VoiceChannel { get; } | |||||
public string VoiceSessionId { get; } | public string VoiceSessionId { get; } | ||||
public bool IsMuted => (_voiceStates & Flags.Muted) != 0; | public bool IsMuted => (_voiceStates & Flags.Muted) != 0; | ||||
@@ -28,9 +28,9 @@ namespace Discord | |||||
public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0; | public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0; | ||||
public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; | public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0; | ||||
public VoiceState(CachedVoiceChannel voiceChannel, Model model) | |||||
public VoiceState(SocketVoiceChannel voiceChannel, Model model) | |||||
: this(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress) { } | : this(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress) { } | ||||
public VoiceState(CachedVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed) | |||||
public VoiceState(SocketVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed) | |||||
{ | { | ||||
VoiceChannel = voiceChannel; | VoiceChannel = voiceChannel; | ||||
VoiceSessionId = sessionId; | VoiceSessionId = sessionId; |