@@ -148,27 +148,6 @@ | |||
<Compile Include="..\Discord.Net\Audio\VoiceBuffer.cs"> | |||
<Link>Audio\VoiceBuffer.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\AsyncCollection.cs"> | |||
<Link>Collections\AsyncCollection.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Channels.cs"> | |||
<Link>Collections\Channels.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Members.cs"> | |||
<Link>Collections\Members.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Messages.cs"> | |||
<Link>Collections\Messages.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Roles.cs"> | |||
<Link>Collections\Roles.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Servers.cs"> | |||
<Link>Collections\Servers.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Collections\Users.cs"> | |||
<Link>Collections\Users.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\DiscordAPIClient.cs"> | |||
<Link>DiscordAPIClient.cs</Link> | |||
</Compile> | |||
@@ -250,6 +229,9 @@ | |||
<Compile Include="..\Discord.Net\HttpException.cs"> | |||
<Link>HttpException.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\AsyncCollection.cs"> | |||
<Link>Models\AsyncCollection.cs</Link> | |||
</Compile> | |||
<Compile Include="..\Discord.Net\Models\Channel.cs"> | |||
<Link>Models\Channel.cs</Link> | |||
</Compile> | |||
@@ -1,47 +0,0 @@ | |||
using System; | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Channels : AsyncCollection<Channel> | |||
{ | |||
public Channels(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
public Channel GetOrAdd(string id, string serverId, string recipientId = null) | |||
=> GetOrAdd(id, () => new Channel(_client, id, serverId, recipientId)); | |||
protected override void OnCreated(Channel item) | |||
{ | |||
if (!item.IsPrivate) | |||
item.Server.AddChannel(item.Id); | |||
if (item.RecipientId != null) | |||
{ | |||
var user = item.Recipient; | |||
if (user.PrivateChannelId != null) | |||
throw new Exception("User already has a private channel."); | |||
user.PrivateChannelId = item.Id; | |||
user.AddRef(); | |||
} | |||
} | |||
protected override void OnRemoved(Channel item) | |||
{ | |||
if (!item.IsPrivate) | |||
{ | |||
var server = item.Server; | |||
if (server != null) | |||
item.Server.RemoveChannel(item.Id); | |||
} | |||
if (item.RecipientId != null) | |||
{ | |||
var user = item.Recipient; | |||
if (user != null) | |||
{ | |||
if (user.PrivateChannelId != item.Id) | |||
throw new Exception("User has a different private channel."); | |||
user.PrivateChannelId = null; | |||
user.RemoveRef(); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -1,42 +0,0 @@ | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Members : AsyncCollection<Member> | |||
{ | |||
public Members(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
private string GetKey(string userId, string serverId) | |||
=> serverId + '_' + userId; | |||
public Member this[string userId, string serverId] | |||
=> this[GetKey(userId, serverId)]; | |||
public Member GetOrAdd(string userId, string serverId) | |||
=> GetOrAdd(GetKey(userId, serverId), () => new Member(_client, userId, serverId)); | |||
public Member TryRemove(string userId, string serverId) | |||
=> TryRemove(GetKey(userId, serverId)); | |||
protected override void OnCreated(Member item) | |||
{ | |||
item.Server.AddMember(item); | |||
item.User.AddServer(item.ServerId); | |||
item.User.AddRef(); | |||
if (item.UserId == _client.CurrentUserId) | |||
item.Server.CurrentMember = item; | |||
} | |||
protected override void OnRemoved(Member item) | |||
{ | |||
var server = item.Server; | |||
if (server != null) | |||
{ | |||
server.RemoveMember(item); | |||
if (item.UserId == _client.CurrentUserId) | |||
server.CurrentMember = null; | |||
} | |||
var user = item.User; | |||
if (user != null) | |||
{ | |||
user.RemoveServer(item.ServerId); | |||
user.RemoveRef(); | |||
} | |||
} | |||
} | |||
} |
@@ -1,26 +0,0 @@ | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Messages : AsyncCollection<Message> | |||
{ | |||
public Messages(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
public Message GetOrAdd(string id, string channelId, string userId) | |||
=> GetOrAdd(id, () => new Message(_client, id, channelId, userId)); | |||
protected override void OnCreated(Message item) | |||
{ | |||
item.Channel.AddMessage(item.Id); | |||
item.User.AddRef(); | |||
} | |||
protected override void OnRemoved(Message item) | |||
{ | |||
var channel = item.Channel; | |||
if (channel != null) | |||
channel.RemoveMessage(item.Id); | |||
var user = item.User; | |||
if (user != null) | |||
user.RemoveRef(); | |||
} | |||
} | |||
} |
@@ -1,22 +0,0 @@ | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Roles : AsyncCollection<Role> | |||
{ | |||
public Roles(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
public Role GetOrAdd(string id, string serverId) | |||
=> GetOrAdd(id, () => new Role(_client, id, serverId)); | |||
protected override void OnCreated(Role item) | |||
{ | |||
item.Server.AddRole(item.Id); | |||
} | |||
protected override void OnRemoved(Role item) | |||
{ | |||
var server = item.Server; | |||
if (server != null) | |||
item.Server.RemoveRole(item.Id); | |||
} | |||
} | |||
} |
@@ -1,30 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Servers : AsyncCollection<Server> | |||
{ | |||
public Servers(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
public Server GetOrAdd(string id) | |||
=> base.GetOrAdd(id, () => new Server(_client, id)); | |||
protected override void OnRemoved(Server item) | |||
{ | |||
var channels = _client.Channels; | |||
foreach (var channelId in item.ChannelIds) | |||
channels.TryRemove(channelId); | |||
var members = _client.Members; | |||
foreach (var userId in item.UserIds) | |||
members.TryRemove(userId, item.Id); | |||
var roles = _client.Roles; | |||
foreach (var roleId in item.RoleIds) | |||
roles.TryRemove(roleId); | |||
} | |||
} | |||
} |
@@ -1,10 +0,0 @@ | |||
namespace Discord.Collections | |||
{ | |||
internal sealed class Users : AsyncCollection<User> | |||
{ | |||
public Users(DiscordClient client, object writerLock) | |||
: base(client, writerLock) { } | |||
public User GetOrAdd(string id) => GetOrAdd(id, () => new User(_client, id)); | |||
} | |||
} |
@@ -5,6 +5,21 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public class BanEventArgs : EventArgs | |||
{ | |||
public User User { get; } | |||
public string UserId { get; } | |||
public Server Server { get; } | |||
public string ServerId => Server.Id; | |||
internal BanEventArgs(User user, string userId, Server server) | |||
{ | |||
User = user; | |||
UserId = userId; | |||
Server = server; | |||
} | |||
} | |||
public partial class DiscordClient | |||
{ | |||
public event EventHandler<BanEventArgs> BanAdded; | |||
@@ -1,4 +1,3 @@ | |||
using Discord.Collections; | |||
using Discord.Net; | |||
using System; | |||
using System.Collections.Generic; | |||
@@ -8,7 +7,16 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public sealed class ChannelEventArgs : EventArgs | |||
internal sealed class Channels : AsyncCollection<Channel> | |||
{ | |||
public Channels(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
public Channel GetOrAdd(string id, string serverId, string recipientId = null) | |||
=> GetOrAdd(id, () => new Channel(_client, id, serverId, recipientId)); | |||
} | |||
public class ChannelEventArgs : EventArgs | |||
{ | |||
public Channel Channel { get; } | |||
public string ChannelId => Channel.Id; | |||
@@ -1,4 +1,3 @@ | |||
using Discord.Collections; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -6,54 +5,66 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public sealed class MemberTypingEventArgs : EventArgs | |||
internal sealed class Members : AsyncCollection<Member> | |||
{ | |||
public Members(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
private string GetKey(string userId, string serverId) | |||
=> serverId + '_' + userId; | |||
public Member this[string userId, string serverId] | |||
=> this[GetKey(userId, serverId)]; | |||
public Member GetOrAdd(string userId, string serverId) | |||
=> GetOrAdd(GetKey(userId, serverId), () => new Member(_client, userId, serverId)); | |||
public Member TryRemove(string userId, string serverId) | |||
=> TryRemove(GetKey(userId, serverId)); | |||
} | |||
public class MemberEventArgs : EventArgs | |||
{ | |||
public Channel Channel { get; } | |||
public string ChannelId => Channel.Id; | |||
public Server Server => Channel.Server; | |||
public string ServerId => Channel.ServerId; | |||
public Member Member { get; } | |||
public string UserId => User.Id; | |||
public User User => Member.User; | |||
public string UserId => Member.UserId; | |||
public Server Server => Member.Server; | |||
public string ServerId => Member.ServerId; | |||
internal MemberEventArgs(Member member) { Member = member; } | |||
} | |||
public class MemberChannelEventArgs : MemberEventArgs | |||
{ | |||
public Channel Channel { get; } | |||
public string ChannelId => Channel.Id; | |||
internal MemberTypingEventArgs(Member member, Channel channel) | |||
internal MemberChannelEventArgs(Member member, Channel channel) | |||
: base(member) | |||
{ | |||
Member = member; | |||
Channel = channel; | |||
} | |||
} | |||
public sealed class MemberIsSpeakingEventArgs : EventArgs | |||
public class MemberIsSpeakingEventArgs : MemberChannelEventArgs | |||
{ | |||
public Channel Channel => Member.VoiceChannel; | |||
public string ChannelId => Member.VoiceChannelId; | |||
public Server Server => Member.Server; | |||
public string ServerId => Member.ServerId; | |||
public User User => Member.User; | |||
public string UserId => Member.UserId; | |||
public Member Member { get; } | |||
public bool IsSpeaking { get; } | |||
internal MemberIsSpeakingEventArgs(Member member, bool isSpeaking) | |||
internal MemberIsSpeakingEventArgs(Member member, Channel channel, bool isSpeaking) | |||
: base(member, channel) | |||
{ | |||
Member = member; | |||
IsSpeaking = isSpeaking; | |||
} | |||
} | |||
public partial class DiscordClient | |||
{ | |||
public event EventHandler<MemberTypingEventArgs> UserIsTyping; | |||
public event EventHandler<MemberChannelEventArgs> UserIsTyping; | |||
private void RaiseUserIsTyping(Member member, Channel channel) | |||
{ | |||
if (UserIsTyping != null) | |||
RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new MemberTypingEventArgs(member, channel))); | |||
RaiseEvent(nameof(UserIsTyping), () => UserIsTyping(this, new MemberChannelEventArgs(member, channel))); | |||
} | |||
public event EventHandler<MemberIsSpeakingEventArgs> UserIsSpeaking; | |||
private void RaiseUserIsSpeaking(Member member, bool isSpeaking) | |||
private void RaiseUserIsSpeaking(Member member, Channel channel, bool isSpeaking) | |||
{ | |||
if (UserIsSpeaking != null) | |||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, isSpeaking))); | |||
RaiseEvent(nameof(UserIsSpeaking), () => UserIsSpeaking(this, new MemberIsSpeakingEventArgs(member, channel, isSpeaking))); | |||
} | |||
internal Members Members => _members; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.API; | |||
using Discord.Collections; | |||
using Discord.Net; | |||
using System; | |||
using System.Collections.Generic; | |||
@@ -9,6 +8,30 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
internal sealed class Messages : AsyncCollection<Message> | |||
{ | |||
public Messages(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
public Message GetOrAdd(string id, string channelId, string userId) | |||
=> GetOrAdd(id, () => new Message(_client, id, channelId, userId)); | |||
} | |||
public class MessageEventArgs : EventArgs | |||
{ | |||
public Message Message { get; } | |||
public string MessageId => Message.Id; | |||
public Member Member => Message.Member; | |||
public Channel Channel => Message.Channel; | |||
public string ChannelId => Message.ChannelId; | |||
public Server Server => Message.Server; | |||
public string ServerId => Message.ServerId; | |||
public User User => Member.User; | |||
public string UserId => Message.UserId; | |||
internal MessageEventArgs(Message msg) { Message = msg; } | |||
} | |||
public partial class DiscordClient | |||
{ | |||
public const int MaxMessageSize = 2000; | |||
@@ -1,4 +1,3 @@ | |||
using Discord.Collections; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -6,6 +5,25 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
internal sealed class Roles : AsyncCollection<Role> | |||
{ | |||
public Roles(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
public Role GetOrAdd(string id, string serverId) | |||
=> GetOrAdd(id, () => new Role(_client, id, serverId)); | |||
} | |||
public class RoleEventArgs : EventArgs | |||
{ | |||
public Role Role { get; } | |||
public string RoleId => Role.Id; | |||
public Server Server => Role.Server; | |||
public string ServerId => Role.ServerId; | |||
internal RoleEventArgs(Role role) { Role = role; } | |||
} | |||
public partial class DiscordClient | |||
{ | |||
public event EventHandler<RoleEventArgs> RoleCreated; | |||
@@ -1,4 +1,3 @@ | |||
using Discord.Collections; | |||
using Discord.Net; | |||
using System; | |||
using System.Collections.Generic; | |||
@@ -8,7 +7,16 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public sealed class ServerEventArgs : EventArgs | |||
internal sealed class Servers : AsyncCollection<Server> | |||
{ | |||
public Servers(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
public Server GetOrAdd(string id) | |||
=> base.GetOrAdd(id, () => new Server(_client, id)); | |||
} | |||
public class ServerEventArgs : EventArgs | |||
{ | |||
public Server Server { get; } | |||
public string ServerId => Server.Id; | |||
@@ -1,5 +1,4 @@ | |||
using Discord.API; | |||
using Discord.Collections; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -7,6 +6,14 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
internal sealed class Users : AsyncCollection<User> | |||
{ | |||
public Users(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
public User GetOrAdd(string id) => GetOrAdd(id, () => new User(_client, id)); | |||
} | |||
public sealed class UserEventArgs : EventArgs | |||
{ | |||
public User User { get; } | |||
@@ -1,5 +1,6 @@ | |||
using Discord.Audio; | |||
using System; | |||
using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
@@ -1,5 +1,4 @@ | |||
using Discord.API; | |||
using Discord.Collections; | |||
using Discord.Net.WebSockets; | |||
using Newtonsoft.Json; | |||
using System; | |||
@@ -10,54 +9,6 @@ using System.Threading.Tasks; | |||
namespace Discord | |||
{ | |||
public sealed class MessageEventArgs : EventArgs | |||
{ | |||
public Message Message { get; } | |||
public string MessageId => Message.Id; | |||
public Member Member => Message.Member; | |||
public Channel Channel => Message.Channel; | |||
public string ChannelId => Message.ChannelId; | |||
public Server Server => Message.Server; | |||
public string ServerId => Message.ServerId; | |||
public User User => Member.User; | |||
public string UserId => Message.UserId; | |||
internal MessageEventArgs(Message msg) { Message = msg; } | |||
} | |||
public sealed class RoleEventArgs : EventArgs | |||
{ | |||
public Role Role { get; } | |||
public string RoleId => Role.Id; | |||
public Server Server => Role.Server; | |||
public string ServerId => Role.ServerId; | |||
internal RoleEventArgs(Role role) { Role = role; } | |||
} | |||
public sealed class BanEventArgs : EventArgs | |||
{ | |||
public User User { get; } | |||
public string UserId { get; } | |||
public Server Server { get; } | |||
public string ServerId => Server.Id; | |||
internal BanEventArgs(User user, string userId, Server server) | |||
{ | |||
User = user; | |||
UserId = userId; | |||
Server = server; | |||
} | |||
} | |||
public sealed class MemberEventArgs : EventArgs | |||
{ | |||
public Member Member { get; } | |||
public User User => Member.User; | |||
public string UserId => Member.UserId; | |||
public Server Server => Member.Server; | |||
public string ServerId => Member.ServerId; | |||
internal MemberEventArgs(Member member) { Member = member; } | |||
} | |||
/// <summary> Provides a connection to the DiscordApp service. </summary> | |||
public partial class DiscordClient : DiscordWSClient | |||
{ | |||
@@ -106,7 +57,7 @@ namespace Discord | |||
if (member.ServerId == e.ServerId && member.IsSpeaking) | |||
{ | |||
member.IsSpeaking = false; | |||
RaiseUserIsSpeaking(member, false); | |||
RaiseUserIsSpeaking(member, _channels[_voiceSocket.CurrentChannelId], false); | |||
} | |||
} | |||
}; | |||
@@ -157,10 +108,10 @@ namespace Discord | |||
$"Deleted Role: {e.Server?.Name ?? "[Private]"}/{e.Role.Name}" + | |||
(showIDs ? $" ({e.ServerId ?? "[Private]"}/{e.RoleId})." : "")); | |||
BanAdded += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Added Ban: {e.Server?.Name ?? "[Private]"}/{e.User?.Name ?? "Unknown"}" + | |||
$"Added Ban: {e.Server?.Name ?? "[Private]"}/{e.User?.Name ?? e.UserId}" + | |||
(showIDs ? $" ({e.ServerId ?? "[Private]"}/{e.UserId})." : "")); | |||
BanRemoved += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Removed Ban: {e.Server?.Name ?? "[Private]"}/{e.User?.Name ?? "Unknown"}" + | |||
$"Removed Ban: {e.Server?.Name ?? "[Private]"}/{e.User?.Name ?? e.UserId}" + | |||
(showIDs ? $" ({e.ServerId ?? "[Private]"}/{e.UserId})." : "")); | |||
UserAdded += (s, e) => RaiseOnLog(LogMessageSeverity.Info, LogMessageSource.Client, | |||
$"Added Member: {e.Server?.Name ?? "[Private]"}/{e.User.Name}" + | |||
@@ -246,7 +197,8 @@ namespace Discord | |||
if (member.IsSpeaking != value) | |||
{ | |||
member.IsSpeaking = value; | |||
RaiseUserIsSpeaking(member, value); | |||
var channel = _channels[_voiceSocket.CurrentChannelId]; | |||
RaiseUserIsSpeaking(member, channel, value); | |||
if (Config.TrackActivity) | |||
member.UpdateActivity(); | |||
} | |||
@@ -665,7 +617,7 @@ namespace Discord | |||
if (data.ChannelId != member.VoiceChannelId && member.IsSpeaking) | |||
{ | |||
member.IsSpeaking = false; | |||
RaiseUserIsSpeaking(member, false); | |||
RaiseUserIsSpeaking(member, _channels[member.VoiceChannelId], false); | |||
} | |||
member.Update(data); | |||
RaiseUserVoiceStateUpdated(member); | |||
@@ -4,7 +4,7 @@ using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
namespace Discord.Collections | |||
namespace Discord | |||
{ | |||
internal abstract class AsyncCollection<TValue> : IEnumerable<TValue> | |||
where TValue : class | |||
@@ -52,13 +52,16 @@ namespace Discord.Collections | |||
protected readonly DiscordClient _client; | |||
protected readonly ConcurrentDictionary<string, TValue> _dictionary; | |||
private readonly Action<TValue> _onCache, _onUncache; | |||
protected AsyncCollection(DiscordClient client, object writerLock) | |||
protected AsyncCollection(DiscordClient client, object writerLock, Action<TValue> onCache, Action<TValue> onUncache) | |||
{ | |||
_client = client; | |||
_writerLock = writerLock; | |||
_dictionary = new ConcurrentDictionary<string, TValue>(); | |||
} | |||
_onCache = onCache; | |||
_onUncache = onUncache; | |||
} | |||
public TValue this[string key] | |||
{ | |||
@@ -85,7 +88,7 @@ namespace Discord.Collections | |||
result = _dictionary.GetOrAdd(key, newItem); | |||
if (result == newItem) | |||
{ | |||
OnCreated(newItem); | |||
_onCache(result); | |||
RaiseItemCreated(result); | |||
} | |||
} | |||
@@ -100,7 +103,7 @@ namespace Discord.Collections | |||
TValue result; | |||
if (_dictionary.TryRemove(key, out result)) | |||
{ | |||
OnRemoved(result); //TODO: If this object is accessed before OnRemoved finished firing, properties such as Server.Channels will have null elements | |||
_onUncache(result); //TODO: If this object is accessed before OnRemoved finished firing, properties such as Server.Channels will have null elements | |||
return result; | |||
} | |||
} | |||
@@ -130,16 +133,7 @@ namespace Discord.Collections | |||
} | |||
} | |||
protected virtual void OnCreated(TValue item) { } | |||
protected virtual void OnRemoved(TValue item) { } | |||
public IEnumerator<TValue> GetEnumerator() | |||
{ | |||
return _dictionary.Select(x => x.Value).GetEnumerator(); | |||
} | |||
IEnumerator IEnumerable.GetEnumerator() | |||
{ | |||
return GetEnumerator(); | |||
} | |||
public IEnumerator<TValue> GetEnumerator() => _dictionary.Select(x => x.Value).GetEnumerator(); | |||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | |||
} | |||
} |
@@ -1,5 +1,6 @@ | |||
using Discord.API; | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
@@ -29,6 +30,7 @@ namespace Discord | |||
private readonly DiscordClient _client; | |||
private readonly ConcurrentDictionary<string, bool> _messages; | |||
private bool _areMembersStale; | |||
private bool _hasRef; | |||
/// <summary> Returns the unique identifier for this channel. </summary> | |||
public string Id { get; } | |||
@@ -101,6 +103,39 @@ namespace Discord | |||
_permissionOverwrites = _initialPermissionsOverwrites; | |||
_areMembersStale = true; | |||
} | |||
internal void OnCached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
server.AddChannel(Id); | |||
if (RecipientId != null) | |||
{ | |||
var user = Recipient; | |||
if (user != null) | |||
{ | |||
user.PrivateChannelId = Id; | |||
user.AddRef(); | |||
_hasRef = true; | |||
} | |||
} | |||
} | |||
internal void OnUncached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
server.RemoveChannel(Id); | |||
if (RecipientId != null) | |||
{ | |||
var user = Recipient; | |||
if (user != null) | |||
{ | |||
user.PrivateChannelId = null; | |||
if (_hasRef) | |||
user.RemoveRef(); | |||
} | |||
} | |||
_hasRef = false; | |||
} | |||
internal void Update(ChannelReference model) | |||
{ | |||
@@ -11,6 +11,7 @@ namespace Discord | |||
{ | |||
private readonly DiscordClient _client; | |||
private ConcurrentDictionary<string, PackedChannelPermissions> _permissions; | |||
private bool _hasRef; | |||
/// <summary> Returns the name of this user on this server. </summary> | |||
public string Name { get; private set; } | |||
@@ -77,6 +78,41 @@ namespace Discord | |||
RoleIds = _initialRoleIds; | |||
_permissions = new ConcurrentDictionary<string, PackedChannelPermissions>(); | |||
} | |||
internal void OnCached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
{ | |||
server.AddMember(this); | |||
if (UserId == _client.CurrentUserId) | |||
server.CurrentMember = this; | |||
} | |||
var user = User; | |||
if (user != null) | |||
{ | |||
user.AddServer(ServerId); | |||
user.AddRef(); | |||
_hasRef = true; | |||
} | |||
} | |||
internal void OnUncached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
{ | |||
server.RemoveMember(this); | |||
if (UserId == _client.CurrentUserId) | |||
server.CurrentMember = null; | |||
} | |||
var user = User; | |||
if (user != null) | |||
{ | |||
user.RemoveServer(ServerId); | |||
if (_hasRef) | |||
user.RemoveRef(); | |||
} | |||
_hasRef = false; | |||
} | |||
public override string ToString() => UserId; | |||
@@ -93,6 +93,7 @@ namespace Discord | |||
private readonly DiscordClient _client; | |||
private string _cleanText; | |||
private bool _gotRef; | |||
/// <summary> Returns the global unique identifier for this message. </summary> | |||
public string Id { get; internal set; } | |||
@@ -154,16 +155,7 @@ namespace Discord | |||
public User User => _client.Users[UserId]; | |||
/// <summary> Returns the author of this message. </summary> | |||
[JsonIgnore] | |||
public Member Member | |||
{ | |||
get | |||
{ | |||
if (!Channel.IsPrivate) | |||
return _client.Members[UserId, ServerId]; | |||
else | |||
throw new InvalidOperationException("Unable to access Member in a private channel. Use User instead or check for Channel.IsPrivate."); | |||
} | |||
} | |||
public Member Member => _client.Members[UserId, ServerId]; | |||
internal Message(DiscordClient client, string id, string channelId, string userId) | |||
{ | |||
@@ -174,6 +166,28 @@ namespace Discord | |||
Attachments = _initialAttachments; | |||
Embeds = _initialEmbeds; | |||
MentionIds = _initialMentions; | |||
} | |||
internal void OnCached() | |||
{ | |||
var channel = Channel; | |||
if (channel != null) | |||
channel.AddMessage(Id); | |||
var user = User; | |||
if (user != null) | |||
{ | |||
user.AddRef(); | |||
_gotRef = true; | |||
} | |||
} | |||
internal void OnUncached() | |||
{ | |||
var channel = Channel; | |||
if (channel != null) | |||
channel.RemoveMessage(Id); | |||
var user = User; | |||
if (user != null && _gotRef) | |||
user.RemoveRef(); | |||
_gotRef = false; | |||
} | |||
internal void Update(MessageInfo model) | |||
@@ -52,7 +52,19 @@ namespace Discord | |||
if (IsEveryone) | |||
Position = int.MinValue; | |||
} | |||
} | |||
internal void OnCached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
server.AddRole(Id); | |||
} | |||
internal void OnUncached() | |||
{ | |||
var server = Server; | |||
if (server != null) | |||
server.RemoveRole(Id); | |||
} | |||
internal void Update(RoleInfo model) | |||
{ | |||
@@ -104,6 +104,23 @@ namespace Discord | |||
_members = new ConcurrentDictionary<string, bool>(); | |||
_roles = new ConcurrentDictionary<string, bool>(); | |||
} | |||
internal void OnCached() | |||
{ | |||
} | |||
internal void OnUncached() | |||
{ | |||
var channels = _client.Channels; | |||
foreach (var channelId in ChannelIds) | |||
channels.TryRemove(channelId); | |||
var members = _client.Members; | |||
foreach (var userId in UserIds) | |||
members.TryRemove(userId, Id); | |||
var roles = _client.Roles; | |||
foreach (var roleId in RoleIds) | |||
roles.TryRemove(roleId); | |||
} | |||
internal void Update(GuildInfo model) | |||
{ | |||
@@ -80,7 +80,13 @@ namespace Discord | |||
_client = client; | |||
Id = id; | |||
_servers = new ConcurrentDictionary<string, bool>(); | |||
} | |||
} | |||
internal void OnCached() | |||
{ | |||
} | |||
internal void OnUncached() | |||
{ | |||
} | |||
internal void Update(UserReference model) | |||
{ | |||