| @@ -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) | |||