Added UsePermissionsCache config, fixed a few permission bugs
This commit is contained in:
@@ -5,64 +5,64 @@ using System.Threading.Tasks;
|
|||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
internal static class TaskExtensions
|
internal static class TaskExtensions
|
||||||
{
|
{
|
||||||
public static async Task Timeout(this Task task, int milliseconds)
|
public static async Task Timeout(this Task task, int milliseconds)
|
||||||
{
|
{
|
||||||
Task timeoutTask = Task.Delay(milliseconds);
|
Task timeoutTask = Task.Delay(milliseconds);
|
||||||
Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
||||||
if (finishedTask == timeoutTask)
|
if (finishedTask == timeoutTask)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
else
|
else
|
||||||
await task.ConfigureAwait(false);
|
await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public static async Task<T> Timeout<T>(this Task<T> task, int milliseconds)
|
public static async Task<T> Timeout<T>(this Task<T> task, int milliseconds)
|
||||||
{
|
{
|
||||||
Task timeoutTask = Task.Delay(milliseconds);
|
Task timeoutTask = Task.Delay(milliseconds);
|
||||||
Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
Task finishedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
||||||
if (finishedTask == timeoutTask)
|
if (finishedTask == timeoutTask)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
else
|
else
|
||||||
return await task.ConfigureAwait(false);
|
return await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
public static async Task Timeout(this Task task, int milliseconds, CancellationTokenSource timeoutToken)
|
public static async Task Timeout(this Task task, int milliseconds, CancellationTokenSource timeoutToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
timeoutToken.CancelAfter(milliseconds);
|
timeoutToken.CancelAfter(milliseconds);
|
||||||
await task.ConfigureAwait(false);
|
await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
if (timeoutToken.IsCancellationRequested)
|
if (timeoutToken.IsCancellationRequested)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static async Task<T> Timeout<T>(this Task<T> task, int milliseconds, CancellationTokenSource timeoutToken)
|
public static async Task<T> Timeout<T>(this Task<T> task, int milliseconds, CancellationTokenSource timeoutToken)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
timeoutToken.CancelAfter(milliseconds);
|
timeoutToken.CancelAfter(milliseconds);
|
||||||
return await task.ConfigureAwait(false);
|
return await task.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
if (timeoutToken.IsCancellationRequested)
|
if (timeoutToken.IsCancellationRequested)
|
||||||
throw new TimeoutException();
|
throw new TimeoutException();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task Wait(this CancellationTokenSource tokenSource)
|
public static async Task Wait(this CancellationTokenSource tokenSource)
|
||||||
{
|
{
|
||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
||||||
catch (OperationCanceledException) { } //Expected
|
catch (OperationCanceledException) { } //Expected
|
||||||
}
|
}
|
||||||
public static async Task Wait(this CancellationToken token)
|
public static async Task Wait(this CancellationToken token)
|
||||||
{
|
{
|
||||||
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
try { await Task.Delay(-1, token).ConfigureAwait(false); }
|
||||||
catch (OperationCanceledException) { } //Expected
|
catch (OperationCanceledException) { } //Expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
namespace Discord
|
namespace Discord
|
||||||
{
|
{
|
||||||
internal static class TaskHelper
|
internal static class TaskHelper
|
||||||
{
|
{
|
||||||
public static Task CompletedTask { get; }
|
public static Task CompletedTask { get; }
|
||||||
static TaskHelper()
|
static TaskHelper()
|
||||||
{
|
{
|
||||||
CompletedTask = Task.Delay(0);
|
CompletedTask = Task.Delay(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,8 +83,11 @@ namespace Discord
|
|||||||
/// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary>
|
/// <summary> Gets or sets the number of messages per channel that should be kept in cache. Setting this to zero disables the message cache entirely. </summary>
|
||||||
public int MessageCacheSize { get { return _messageCacheSize; } set { SetValue(ref _messageCacheSize, value); } }
|
public int MessageCacheSize { get { return _messageCacheSize; } set { SetValue(ref _messageCacheSize, value); } }
|
||||||
private int _messageCacheSize = 100;
|
private int _messageCacheSize = 100;
|
||||||
/// <summary> Maintains the LastActivity property for users, showing when they last made an action (sent message, joined server, typed, etc). </summary>
|
/// <summary> Gets or sets whether the permissions cache should be used. This makes operations such as User.GetPermissions(Channel), User.ServerPermissions and Channel.Members </summary>
|
||||||
public bool TrackActivity { get { return _trackActivity; } set { SetValue(ref _trackActivity, value); } }
|
public bool UsePermissionsCache { get { return _usePermissionsCache; } set { SetValue(ref _usePermissionsCache, value); } }
|
||||||
|
private bool _usePermissionsCache = true;
|
||||||
|
/// <summary> Maintains the LastActivity property for users, showing when they last made an action (sent message, joined server, typed, etc). </summary>
|
||||||
|
public bool TrackActivity { get { return _trackActivity; } set { SetValue(ref _trackActivity, value); } }
|
||||||
private bool _trackActivity = true;
|
private bool _trackActivity = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,12 +68,30 @@ namespace Discord
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Type == ChannelType.Text)
|
if (IsPrivate)
|
||||||
return _members.Values.Where(x => x.Permissions.ReadMessages == true).Select(x => x.User);
|
return _members.Values.Select(x => x.User);
|
||||||
else if (Type == ChannelType.Voice)
|
if (_client.Config.UsePermissionsCache)
|
||||||
return _members.Values.Select(x => x.User).Where(x => x.VoiceChannel == this);
|
{
|
||||||
else
|
if (Type == ChannelType.Text)
|
||||||
return Enumerable.Empty<User>();
|
return _members.Values.Where(x => x.Permissions.ReadMessages == true).Select(x => x.User);
|
||||||
|
else if (Type == ChannelType.Voice)
|
||||||
|
return _members.Values.Select(x => x.User).Where(x => x.VoiceChannel == this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Type == ChannelType.Text)
|
||||||
|
{
|
||||||
|
ChannelPermissions perms = new ChannelPermissions();
|
||||||
|
return Server.Members.Where(x =>
|
||||||
|
{
|
||||||
|
UpdatePermissions(x, perms);
|
||||||
|
return perms.ReadMessages == true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (Type == ChannelType.Voice)
|
||||||
|
return Server.Members.Where(x => x.VoiceChannel == this);
|
||||||
|
}
|
||||||
|
return Enumerable.Empty<User>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
@@ -115,13 +133,13 @@ namespace Discord
|
|||||||
x.Global.PrivateChannel = null;
|
x.Global.PrivateChannel = null;
|
||||||
});
|
});
|
||||||
_permissionOverwrites = new PermissionOverwrite[0];
|
_permissionOverwrites = new PermissionOverwrite[0];
|
||||||
_members = new ConcurrentDictionary<long, ChannelMember>();
|
_members = new ConcurrentDictionary<long, ChannelMember>();
|
||||||
|
|
||||||
if (recipientId != null)
|
if (recipientId != null)
|
||||||
{
|
{
|
||||||
AddMember(client.PrivateUser);
|
AddMember(client.PrivateUser);
|
||||||
AddMember(Recipient);
|
AddMember(Recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Local Cache
|
//Local Cache
|
||||||
if (client.Config.MessageCacheSize > 0)
|
if (client.Config.MessageCacheSize > 0)
|
||||||
@@ -190,40 +208,61 @@ namespace Discord
|
|||||||
internal void RemoveMessage(Message message) => _messages.TryRemove(message.Id, out message);
|
internal void RemoveMessage(Message message) => _messages.TryRemove(message.Id, out message);
|
||||||
|
|
||||||
internal void AddMember(User user)
|
internal void AddMember(User user)
|
||||||
{
|
{
|
||||||
var member = new ChannelMember(user);
|
if (!_client.Config.UsePermissionsCache)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var member = new ChannelMember(user);
|
||||||
if (_members.TryAdd(user.Id, member))
|
if (_members.TryAdd(user.Id, member))
|
||||||
UpdatePermissions(user, member.Permissions);
|
UpdatePermissions(user, member.Permissions);
|
||||||
}
|
}
|
||||||
internal void RemoveMember(User user)
|
internal void RemoveMember(User user)
|
||||||
{
|
{
|
||||||
ChannelMember ignored;
|
if (!_client.Config.UsePermissionsCache)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ChannelMember ignored;
|
||||||
_members.TryRemove(user.Id, out ignored);
|
_members.TryRemove(user.Id, out ignored);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ChannelPermissions GetPermissions(User user)
|
internal ChannelPermissions GetPermissions(User user)
|
||||||
{
|
{
|
||||||
ChannelMember member;
|
if (_client.Config.UsePermissionsCache)
|
||||||
if (_members.TryGetValue(user.Id, out member))
|
{
|
||||||
return member.Permissions;
|
ChannelMember member;
|
||||||
else
|
if (_members.TryGetValue(user.Id, out member))
|
||||||
return null;
|
return member.Permissions;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ChannelPermissions perms = new ChannelPermissions();
|
||||||
|
UpdatePermissions(user, perms);
|
||||||
|
return perms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
internal void UpdatePermissions()
|
internal void UpdatePermissions()
|
||||||
{
|
{
|
||||||
foreach (var pair in _members)
|
if (!_client.Config.UsePermissionsCache)
|
||||||
{
|
return;
|
||||||
ChannelMember member = pair.Value;
|
|
||||||
UpdatePermissions(member.User, member.Permissions);
|
foreach (var pair in _members)
|
||||||
}
|
{
|
||||||
|
ChannelMember member = pair.Value;
|
||||||
|
UpdatePermissions(member.User, member.Permissions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
internal void UpdatePermissions(User user)
|
internal void UpdatePermissions(User user)
|
||||||
{
|
{
|
||||||
ChannelMember member;
|
if (!_client.Config.UsePermissionsCache)
|
||||||
if (_members.TryGetValue(user.Id, out member))
|
return;
|
||||||
UpdatePermissions(member.User, member.Permissions);
|
|
||||||
|
ChannelMember member;
|
||||||
|
if (_members.TryGetValue(user.Id, out member))
|
||||||
|
UpdatePermissions(member.User, member.Permissions);
|
||||||
}
|
}
|
||||||
private void UpdatePermissions(User user, ChannelPermissions permissions)
|
internal void UpdatePermissions(User user, ChannelPermissions permissions)
|
||||||
{
|
{
|
||||||
uint newPermissions = 0;
|
uint newPermissions = 0;
|
||||||
var server = Server;
|
var server = Server;
|
||||||
@@ -236,7 +275,7 @@ namespace Discord
|
|||||||
//Start with this user's server permissions
|
//Start with this user's server permissions
|
||||||
newPermissions = server.GetPermissions(user).RawValue;
|
newPermissions = server.GetPermissions(user).RawValue;
|
||||||
|
|
||||||
if (IsPrivate || server.Owner == user)
|
if (IsPrivate || user.IsOwner)
|
||||||
newPermissions = mask; //Owners always have all permissions
|
newPermissions = mask; //Owners always have all permissions
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -263,7 +302,8 @@ namespace Discord
|
|||||||
else
|
else
|
||||||
newPermissions = mask; //Private messages always have all permissions
|
newPermissions = mask; //Private messages always have all permissions
|
||||||
|
|
||||||
permissions.SetRawValueInternal(newPermissions);
|
if (newPermissions != permissions.RawValue)
|
||||||
|
permissions.SetRawValueInternal(newPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj) => obj is Channel && (obj as Channel).Id == Id;
|
public override bool Equals(object obj) => obj is Channel && (obj as Channel).Id == Id;
|
||||||
|
|||||||
@@ -38,14 +38,11 @@ namespace Discord
|
|||||||
/// <summary> Returns the URL to this user's current avatar. </summary>
|
/// <summary> Returns the URL to this user's current avatar. </summary>
|
||||||
public string IconUrl => IconId != null ? Endpoints.ServerIcon(Id, IconId) : null;
|
public string IconUrl => IconId != null ? Endpoints.ServerIcon(Id, IconId) : null;
|
||||||
|
|
||||||
/// <summary> Returns true if the current user created this server. </summary>
|
|
||||||
public bool IsOwner => _client.CurrentUser.Id == _owner.Id;
|
|
||||||
|
|
||||||
/// <summary> Returns the user that first created this server. </summary>
|
/// <summary> Returns the user that first created this server. </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public User Owner => _owner.Value;
|
public User Owner => _owner.Value;
|
||||||
[JsonProperty]
|
[JsonProperty]
|
||||||
private long? OwnerId => _owner.Id;
|
internal long? OwnerId => _owner.Id;
|
||||||
private Reference<User> _owner;
|
private Reference<User> _owner;
|
||||||
|
|
||||||
/// <summary> Returns the AFK voice channel for this server (see AFKTimeout). </summary>
|
/// <summary> Returns the AFK voice channel for this server (see AFKTimeout). </summary>
|
||||||
@@ -110,6 +107,7 @@ namespace Discord
|
|||||||
internal override bool LoadReferences()
|
internal override bool LoadReferences()
|
||||||
{
|
{
|
||||||
_afkChannel.Load();
|
_afkChannel.Load();
|
||||||
|
_owner.Load();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
internal override void UnloadReferences()
|
internal override void UnloadReferences()
|
||||||
@@ -185,7 +183,7 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
|
|
||||||
var usersCache = _client.Users;
|
var usersCache = _client.Users;
|
||||||
foreach (var subModel in model.Members)
|
foreach (var subModel in model.Members)
|
||||||
{
|
{
|
||||||
var user = usersCache.GetOrAdd(subModel.User.Id, Id);
|
var user = usersCache.GetOrAdd(subModel.User.Id, Id);
|
||||||
user.Update(subModel);
|
user.Update(subModel);
|
||||||
@@ -279,10 +277,9 @@ namespace Discord
|
|||||||
}
|
}
|
||||||
private void UpdatePermissions(User user, ServerPermissions permissions)
|
private void UpdatePermissions(User user, ServerPermissions permissions)
|
||||||
{
|
{
|
||||||
uint oldPermissions = permissions.RawValue;
|
|
||||||
uint newPermissions = 0;
|
uint newPermissions = 0;
|
||||||
|
|
||||||
if (Owner == user)
|
if (user.IsOwner)
|
||||||
newPermissions = ServerPermissions.All.RawValue;
|
newPermissions = ServerPermissions.All.RawValue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -294,7 +291,7 @@ namespace Discord
|
|||||||
if (BitHelper.GetBit(newPermissions, (int)PermissionsBits.ManageRolesOrPermissions))
|
if (BitHelper.GetBit(newPermissions, (int)PermissionsBits.ManageRolesOrPermissions))
|
||||||
newPermissions = ServerPermissions.All.RawValue;
|
newPermissions = ServerPermissions.All.RawValue;
|
||||||
|
|
||||||
if (newPermissions != oldPermissions)
|
if (newPermissions != permissions.RawValue)
|
||||||
{
|
{
|
||||||
permissions.SetRawValueInternal(newPermissions);
|
permissions.SetRawValueInternal(newPermissions);
|
||||||
foreach (var channel in _channels)
|
foreach (var channel in _channels)
|
||||||
|
|||||||
Reference in New Issue
Block a user