@@ -20,7 +20,7 @@ namespace Discord.API | |||
[JsonProperty("afk_channel_id")] | |||
public string AFKChannelId; | |||
[JsonProperty("afk_timeout")] | |||
public int AFKTimeout; | |||
public int? AFKTimeout; | |||
[JsonProperty("embed_channel_id")] | |||
public string EmbedChannelId; | |||
[JsonProperty("embed_enabled")] | |||
@@ -7,9 +7,25 @@ namespace Discord | |||
{ | |||
internal sealed class Roles : AsyncCollection<Role> | |||
{ | |||
private const string VirtualEveryoneId = "[Virtual]"; | |||
public Role VirtualEveryone { get; private set; } | |||
public Roles(DiscordClient client, object writerLock) | |||
: base(client, writerLock, x => x.OnCached(), x => x.OnUncached()) { } | |||
internal Role CreateVirtualRole(string serverId, string name) | |||
{ | |||
var role = new Role(_client, serverId, serverId); | |||
_dictionary[serverId] = role; | |||
role.Update(new API.RoleInfo | |||
{ | |||
Id = serverId, | |||
Name = name, | |||
Permissions = ChannelPermissions.None.RawValue | |||
}); | |||
return role; | |||
} | |||
public Role GetOrAdd(string id, string serverId) | |||
=> GetOrAdd(id, () => new Role(_client, id, serverId)); | |||
} | |||
@@ -8,8 +8,6 @@ namespace Discord | |||
{ | |||
internal sealed class Servers : AsyncCollection<Server> | |||
{ | |||
private const string PMServerId = "Private"; | |||
public Server PMServer { get; private set; } | |||
public Servers(DiscordClient client, object writerLock) | |||
@@ -17,9 +15,27 @@ namespace Discord | |||
protected override void Initialize() | |||
{ | |||
PMServer = new Server(_client, PMServerId) { IsVirtual = true }; | |||
PMServer.Update(new API.ExtendedGuildInfo { Id = PMServerId, Name = PMServerId }); | |||
_dictionary[PMServerId] = PMServer; | |||
PMServer = CreateVirtualServer("Private"); | |||
} | |||
private Server CreateVirtualServer(string name) | |||
{ | |||
string id = $"[{name}]"; | |||
var server = new Server(_client, id) { IsVirtual = true }; | |||
_dictionary[id] = server; | |||
var everyone = _client.Roles.CreateVirtualRole(id, "@everyone"); | |||
server.Update(new API.GuildInfo | |||
{ | |||
Id = id, | |||
Name = id, | |||
JoinedAt = DateTime.UtcNow, | |||
Roles = new API.RoleInfo[] { new API.RoleInfo { | |||
Id = everyone.Id, | |||
Name = everyone.Name | |||
} } | |||
}); | |||
return server; | |||
} | |||
public Server GetOrAdd(string id) | |||
@@ -42,6 +42,14 @@ namespace Discord | |||
_roles = new Roles(this, cacheLock); | |||
_servers = new Servers(this, cacheLock); | |||
_users = new Users(this, cacheLock); | |||
_channels.Clear(); | |||
_members.Clear(); | |||
_messages.Clear(); | |||
_roles.Clear(); | |||
_servers.Clear(); | |||
_users.Clear(); | |||
_status = UserStatus.Online; | |||
this.Connected += async (s, e) => | |||
@@ -61,7 +61,6 @@ namespace Discord | |||
_dictionary = new ConcurrentDictionary<string, TValue>(); | |||
_onCache = onCache; | |||
_onUncache = onUncache; | |||
Initialize(); | |||
} | |||
protected virtual void Initialize() { } | |||
@@ -44,7 +44,7 @@ namespace Discord | |||
/// <summary> Returns the position of this channel in the channel list for this server. </summary> | |||
public int Position { get; private set; } | |||
/// <summary> Returns false is this is a public chat and true if this is a private chat with another user (see Recipient). </summary> | |||
public bool IsPrivate => ServerId == null; | |||
public bool IsPrivate => RecipientId != null; | |||
/// <summary> Returns the type of this channel (see ChannelTypes). </summary> | |||
public string Type { get; private set; } | |||
@@ -108,15 +108,31 @@ namespace Discord | |||
var server = Server; | |||
if (server != null) | |||
server.AddChannel(Id); | |||
if (RecipientId != null) | |||
if (IsPrivate) | |||
{ | |||
var user = Recipient; | |||
if (user != null) | |||
{ | |||
Name = "@" + user.Name; | |||
user.PrivateChannelId = Id; | |||
user.AddRef(); | |||
_hasRef = true; | |||
} | |||
else | |||
Name = "@" + RecipientId; | |||
var member = _client.Members.GetOrAdd(RecipientId, ServerId); | |||
member.Update(new ExtendedMemberInfo | |||
{ | |||
GuildId = ServerId, | |||
UserId = RecipientId, | |||
JoinedAt = DateTime.UtcNow, | |||
Roles = new string[0] | |||
}); | |||
_permissionOverwrites = new PermissionOverwrite[] | |||
{ | |||
new PermissionOverwrite(PermissionTarget.Member, _client.CurrentUserId, ChannelPermissions.AllPrivate.RawValue, 0), | |||
new PermissionOverwrite(PermissionTarget.Member, RecipientId, ChannelPermissions.AllPrivate.RawValue, 0) | |||
}; | |||
} | |||
} | |||
internal void OnUncached() | |||
@@ -124,7 +140,7 @@ namespace Discord | |||
var server = Server; | |||
if (server != null) | |||
server.RemoveChannel(Id); | |||
if (RecipientId != null) | |||
if (IsPrivate) | |||
{ | |||
var user = Recipient; | |||
if (user != null) | |||
@@ -133,13 +149,14 @@ namespace Discord | |||
if (_hasRef) | |||
user.RemoveRef(); | |||
} | |||
} | |||
_client.Members.TryRemove(RecipientId, ServerId); | |||
} | |||
_hasRef = false; | |||
} | |||
internal void Update(ChannelReference model) | |||
{ | |||
if (model.Name != null) | |||
if (!IsPrivate && model.Name != null) | |||
Name = model.Name; | |||
if (model.Type != null) | |||
Type = model.Type; | |||
@@ -217,7 +217,7 @@ namespace Discord | |||
uint oldPermissions = permissions.RawValue; | |||
if (UserId == server.OwnerId) | |||
newPermissions = ChannelPermissions.All.RawValue; | |||
newPermissions = ChannelPermissions.All(channel).RawValue; | |||
else | |||
{ | |||
if (channel == null) return; | |||
@@ -240,7 +240,7 @@ namespace Discord | |||
permissions.SetRawValueInternal(newPermissions); | |||
if (permissions.General_ManagePermissions) | |||
permissions.SetRawValueInternal(ChannelPermissions.All.RawValue); | |||
permissions.SetRawValueInternal(ChannelPermissions.All(channel).RawValue); | |||
/*else if (server.DefaultChannelId == channelId) | |||
permissions.SetBitInternal(PackedPermissions.Text_ReadMessagesBit, true);*/ | |||
@@ -4,14 +4,16 @@ namespace Discord | |||
{ | |||
public sealed class ServerPermissions : Permissions | |||
{ | |||
public static ServerPermissions None { get; } | |||
public static ServerPermissions All { get; } | |||
private static readonly ServerPermissions _none, _all; | |||
public static ServerPermissions None => _none; | |||
public static ServerPermissions All => _all; | |||
static ServerPermissions() | |||
{ | |||
None = new ServerPermissions(); | |||
None.Lock(); | |||
All = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); | |||
All.Lock(); | |||
_none = new ServerPermissions(); | |||
_none.Lock(); | |||
_all = new ServerPermissions(Convert.ToUInt32("00000011111100111111110000111111", 2)); | |||
_all.Lock(); | |||
} | |||
public ServerPermissions(uint rawValue = 0) : base(rawValue) { } | |||
@@ -32,15 +34,38 @@ namespace Discord | |||
public sealed class ChannelPermissions : Permissions | |||
{ | |||
public static ChannelPermissions None { get; } | |||
public static ChannelPermissions All { get; } | |||
private static readonly ChannelPermissions _none, _all, _allText, _allVoice, _allPM; | |||
public static ChannelPermissions None => _none; | |||
public static ChannelPermissions AllMask => _all; | |||
public static ChannelPermissions AllText => _allText; | |||
public static ChannelPermissions AllVoice => _allVoice; | |||
public static ChannelPermissions AllPrivate => _allPM; | |||
static ChannelPermissions() | |||
{ | |||
None = new ChannelPermissions(); | |||
None.Lock(); | |||
All = new ChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); | |||
All.Lock(); | |||
} | |||
_none = new ChannelPermissions(); | |||
_none.Lock(); | |||
_all = new ChannelPermissions(Convert.ToUInt32("00000011111100111111110000011001", 2)); | |||
_all.Lock(); | |||
_allText = new ChannelPermissions(Convert.ToUInt32("00000000000000111111110000011001", 2)); | |||
_allText.Lock(); | |||
_allVoice = new ChannelPermissions(Convert.ToUInt32("00000011111100000000000000011001", 2)); | |||
_allVoice.Lock(); | |||
_allPM = new ChannelPermissions(Convert.ToUInt32("00000000000000011100110000000000", 2)); | |||
_allPM.Lock(); | |||
} | |||
public static ChannelPermissions All(Channel channel) | |||
{ | |||
if (channel.IsPrivate) | |||
return _allPM; | |||
else if (channel.Type == ChannelTypes.Text) | |||
return _allText; | |||
else if (channel.Type == ChannelTypes.Voice) | |||
return _allText; | |||
else | |||
return _none; | |||
} | |||
public ChannelPermissions(uint rawValue = 0) : base(rawValue) { } | |||
@@ -126,19 +126,28 @@ namespace Discord | |||
internal void Update(GuildInfo model) | |||
{ | |||
//Can be null | |||
AFKChannelId = model.AFKChannelId; | |||
AFKTimeout = model.AFKTimeout; | |||
if (model.JoinedAt.HasValue) | |||
if (model.AFKTimeout != null) | |||
AFKTimeout = model.AFKTimeout.Value; | |||
if (model.JoinedAt != null) | |||
JoinedAt = model.JoinedAt.Value; | |||
Name = model.Name; | |||
OwnerId = model.OwnerId; | |||
Region = model.Region; | |||
if (model.Name != null) | |||
Name = model.Name; | |||
if (model.OwnerId != null) | |||
OwnerId = model.OwnerId; | |||
if (model.Region != null) | |||
Region = model.Region; | |||
var roles = _client.Roles; | |||
foreach (var subModel in model.Roles) | |||
if (model.Roles != null) | |||
{ | |||
var role = roles.GetOrAdd(subModel.Id, Id); | |||
role.Update(subModel); | |||
var roles = _client.Roles; | |||
foreach (var subModel in model.Roles) | |||
{ | |||
var role = roles.GetOrAdd(subModel.Id, Id); | |||
role.Update(subModel); | |||
} | |||
} | |||
} | |||
internal void Update(ExtendedGuildInfo model) | |||