@@ -3,6 +3,7 @@ | |||
internal static class Endpoints | |||
{ | |||
public static readonly string BaseUrl = "discordapp.com"; | |||
public static readonly string BaseShortUrl = "discord.gg"; | |||
public static readonly string BaseHttps = $"https://{BaseUrl}"; | |||
// /api | |||
@@ -49,5 +50,8 @@ | |||
//Web Sockets | |||
public static readonly string BaseWss = "wss://" + BaseUrl; | |||
public static readonly string WebSocket_Hub = $"{BaseWss}/hub"; | |||
//Website | |||
public static string InviteUrl(string code) => $"{BaseShortUrl}/{code}"; | |||
} | |||
} |
@@ -117,7 +117,7 @@ namespace Discord.API.Models | |||
public class Membership | |||
{ | |||
[JsonProperty(PropertyName = "roles")] | |||
public object[] Roles; | |||
public string[] Roles; | |||
[JsonProperty(PropertyName = "mute")] | |||
public bool IsMuted; | |||
[JsonProperty(PropertyName = "deaf")] | |||
@@ -48,12 +48,12 @@ namespace Discord.API.Models | |||
[JsonProperty(PropertyName = "joined_at")] | |||
public DateTime JoinedAt; | |||
[JsonProperty(PropertyName = "roles")] | |||
public object[] Roles; | |||
public string[] Roles; | |||
} | |||
public sealed class GuildMemberUpdate : GuildMemberEvent | |||
{ | |||
[JsonProperty(PropertyName = "roles")] | |||
public object[] Roles; | |||
public string[] Roles; | |||
} | |||
public sealed class GuildMemberRemove : GuildMemberEvent { } | |||
@@ -55,6 +55,7 @@ | |||
<Compile Include="ChannelTypes.cs" /> | |||
<Compile Include="Helpers\AsyncCache.cs" /> | |||
<Compile Include="Invite.cs" /> | |||
<Compile Include="Membership.cs" /> | |||
<Compile Include="Role.cs" /> | |||
<Compile Include="Message.cs" /> | |||
<Compile Include="Channel.cs" /> | |||
@@ -176,32 +176,27 @@ namespace Discord | |||
//Member | |||
public sealed class MemberEventArgs : EventArgs | |||
{ | |||
public readonly User User; | |||
public readonly Server Server; | |||
internal MemberEventArgs(User user, Server server) | |||
{ | |||
User = user; | |||
Server = server; | |||
} | |||
public readonly Membership Membership; | |||
internal MemberEventArgs(Membership membership) { Membership = membership; } | |||
} | |||
public event EventHandler<MemberEventArgs> MemberAdded; | |||
private void RaiseMemberAdded(User user, Server server) | |||
private void RaiseMemberAdded(Membership membership, Server server) | |||
{ | |||
if (MemberAdded != null) | |||
MemberAdded(this, new MemberEventArgs(user, server)); | |||
MemberAdded(this, new MemberEventArgs(membership)); | |||
} | |||
public event EventHandler<MemberEventArgs> MemberRemoved; | |||
private void RaiseMemberRemoved(User user, Server server) | |||
private void RaiseMemberRemoved(Membership membership, Server server) | |||
{ | |||
if (MemberRemoved != null) | |||
MemberRemoved(this, new MemberEventArgs(user, server)); | |||
MemberRemoved(this, new MemberEventArgs(membership)); | |||
} | |||
public event EventHandler<MemberEventArgs> MemberUpdated; | |||
private void RaiseMemberUpdated(User user, Server server) | |||
private void RaiseMemberUpdated(Membership membership, Server server) | |||
{ | |||
if (MemberUpdated != null) | |||
MemberUpdated(this, new MemberEventArgs(user, server)); | |||
MemberUpdated(this, new MemberEventArgs(membership)); | |||
} | |||
//Status | |||
@@ -71,7 +71,7 @@ namespace Discord | |||
foreach (var channel in extendedModel.Channels) | |||
{ | |||
_channels.Update(channel.Id, model.Id, channel); | |||
if (channel.Type == ChannelTypes.Text) | |||
/*if (channel.Type == ChannelTypes.Text) | |||
{ | |||
try | |||
{ | |||
@@ -84,12 +84,12 @@ namespace Discord | |||
} | |||
} | |||
catch { } //Bad Permissions? | |||
} | |||
}*/ | |||
} | |||
foreach (var membership in extendedModel.Members) | |||
{ | |||
_users.Update(membership.User.Id, membership.User); | |||
server.AddMember(membership.User.Id); | |||
server.AddMember(new Membership(server.Id, membership.User.Id, membership.JoinedAt, this) { RoleIds = membership.Roles, IsMuted = membership.IsMuted, IsDeafened = membership.IsDeaf }); | |||
} | |||
} | |||
}, | |||
@@ -118,12 +118,13 @@ namespace Discord | |||
{ | |||
var extendedModel = model as API.Models.Message; | |||
message.Attachments = extendedModel.Attachments; | |||
message.Text = extendedModel.Content; | |||
message.Embeds = extendedModel.Embeds; | |||
message.IsMentioningEveryone = extendedModel.IsMentioningEveryone; | |||
message.IsTTS = extendedModel.IsTextToSpeech; | |||
message.UserId = extendedModel.Author.Id; | |||
message.MentionIds = extendedModel.Mentions.Select(x => x.Id).ToArray(); | |||
message.UserId = extendedModel.Author.Id; | |||
message.Timestamp = extendedModel.Timestamp; | |||
message.Text = extendedModel.Content; | |||
} | |||
if (model is WebSocketEvents.MessageUpdate) | |||
{ | |||
@@ -137,8 +138,9 @@ namespace Discord | |||
(key, parentKey) => new Role(key, parentKey, this), | |||
(role, model) => | |||
{ | |||
role.Name = model.Name; | |||
role.Permissions = model.Permissions; | |||
}, | |||
}, | |||
role => { } | |||
); | |||
_users = new AsyncCache<User, API.Models.UserReference>( | |||
@@ -153,13 +155,13 @@ namespace Discord | |||
var extendedModel = model as SelfUserInfo; | |||
user.Email = extendedModel.Email; | |||
user.IsVerified = extendedModel.IsVerified; | |||
} | |||
} | |||
if (model is PresenceUserInfo) | |||
{ | |||
var extendedModel = model as PresenceUserInfo; | |||
user.GameId = extendedModel.GameId; | |||
user.Status = extendedModel.Status; | |||
} | |||
} | |||
}, | |||
user => { } | |||
); | |||
@@ -261,8 +263,9 @@ namespace Discord | |||
var data = e.Event.ToObject<WebSocketEvents.GuildMemberAdd>(); | |||
var user = _users.Update(data.User.Id, data.User); | |||
var server = _servers[data.GuildId]; | |||
server._members[user.Id] = true; | |||
RaiseMemberAdded(user, server); | |||
var membership = new Membership(server.Id, data.User.Id, data.JoinedAt, this) { RoleIds = data.Roles }; | |||
server.AddMember(membership); | |||
RaiseMemberAdded(membership, server); | |||
} | |||
break; | |||
case "GUILD_MEMBER_UPDATE": | |||
@@ -270,7 +273,10 @@ namespace Discord | |||
var data = e.Event.ToObject<WebSocketEvents.GuildMemberUpdate>(); | |||
var user = _users.Update(data.User.Id, data.User); | |||
var server = _servers[data.GuildId]; | |||
RaiseMemberUpdated(user, server); | |||
var membership = server.GetMembership(data.User.Id); | |||
if (membership != null) | |||
membership.RoleIds = data.Roles; | |||
RaiseMemberUpdated(membership, server); | |||
} | |||
break; | |||
case "GUILD_MEMBER_REMOVE": | |||
@@ -278,8 +284,12 @@ namespace Discord | |||
var data = e.Event.ToObject<WebSocketEvents.GuildMemberRemove>(); | |||
var user = _users.Update(data.User.Id, data.User); | |||
var server = _servers[data.GuildId]; | |||
if (server != null && server.RemoveMember(user.Id)) | |||
RaiseMemberRemoved(user, server); | |||
if (server != null) | |||
{ | |||
var membership = server.RemoveMember(user.Id); | |||
if (membership != null) | |||
RaiseMemberRemoved(membership, server); | |||
} | |||
} | |||
break; | |||
@@ -287,14 +297,14 @@ namespace Discord | |||
case "GUILD_ROLE_CREATE": | |||
{ | |||
var data = e.Event.ToObject<WebSocketEvents.GuildRoleCreateUpdate>(); | |||
var role = _roles.Update(data.Role.Id, data.Role); | |||
var role = _roles.Update(data.Role.Id, data.GuildId, data.Role); | |||
RaiseRoleCreated(role); | |||
} | |||
break; | |||
case "GUILD_ROLE_UPDATE": | |||
{ | |||
var data = e.Event.ToObject<WebSocketEvents.GuildRoleCreateUpdate>(); | |||
var role = _roles.Update(data.Role.Id, data.Role); | |||
var role = _roles.Update(data.Role.Id, data.GuildId, data.Role); | |||
RaiseRoleUpdated(role); | |||
} | |||
break; | |||
@@ -454,7 +464,9 @@ namespace Discord | |||
} | |||
public Role GetRole(string id) => _roles[id]; | |||
public Role FindRole(string name) | |||
public Role FindRole(Server server, string name) | |||
=> FindRole(server.Id, name); | |||
public Role FindRole(string serverId, string name) | |||
{ | |||
return _roles | |||
.Where(x => string.Equals(x.Name, name, StringComparison.InvariantCultureIgnoreCase)) | |||
@@ -515,13 +527,13 @@ namespace Discord | |||
} | |||
//Channels | |||
public Task<Channel> CreateChannel(Server server, string name, string region) | |||
=> CreateChannel(server.Id, name, region); | |||
public async Task<Channel> CreateChannel(string serverId, string name, string region) | |||
public Task<Channel> CreateChannel(Server server, string name, string type) | |||
=> CreateChannel(server.Id, name, type); | |||
public async Task<Channel> CreateChannel(string serverId, string name, string type) | |||
{ | |||
CheckReady(); | |||
var response = await DiscordAPI.CreateChannel(serverId, name, region, _httpOptions); | |||
return _channels.Update(response.Id, response); | |||
var response = await DiscordAPI.CreateChannel(serverId, name, type, _httpOptions); | |||
return _channels.Update(response.Id, serverId, response); | |||
} | |||
public Task<Channel> CreatePMChannel(User user) | |||
=> CreatePMChannel(user.Id); | |||
@@ -10,6 +10,8 @@ namespace Discord | |||
public bool IsRevoked, IsTemporary; | |||
public readonly string Code, XkcdPass; | |||
public string Url { get { return API.Endpoints.InviteUrl(XkcdPass ?? Code); } } | |||
public string InviterId { get; internal set; } | |||
[JsonIgnore] | |||
public User Inviter { get { return _client.GetUser(InviterId); } } | |||
@@ -0,0 +1,33 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
namespace Discord | |||
{ | |||
public class Membership | |||
{ | |||
private readonly DiscordClient _client; | |||
public DateTime JoinedAt; | |||
public bool IsMuted { get; internal set; } | |||
public bool IsDeafened { get; internal set; } | |||
public string ServerId { get; } | |||
public Server Server { get { return _client.GetServer(ServerId); } } | |||
public string UserId { get; } | |||
public User User { get { return _client.GetUser(UserId); } } | |||
public string[] RoleIds { get; internal set; } | |||
public IEnumerable<Role> Roles { get { return RoleIds.Select(x => _client.GetRole((string)x)); } } | |||
public Membership(string serverId, string userId, DateTime joinedAt, DiscordClient client) | |||
{ | |||
ServerId = serverId; | |||
UserId = userId; | |||
_client = client; | |||
JoinedAt = joinedAt; | |||
} | |||
} | |||
} |
@@ -1,5 +1,7 @@ | |||
using Newtonsoft.Json; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
namespace Discord | |||
{ | |||
@@ -14,6 +16,10 @@ namespace Discord | |||
public string Text { get; internal set; } | |||
public DateTime Timestamp { get; internal set; } | |||
public string[] MentionIds { get; internal set; } | |||
[JsonIgnore] | |||
public IEnumerable<User> Mentions { get { return MentionIds.Select(x => _client.GetUser(x)).Where(x => x != null); } } | |||
public string ChannelId { get; } | |||
[JsonIgnore] | |||
public Channel Channel { get { return _client.GetChannel(ChannelId); } } | |||
@@ -9,5 +9,5 @@ | |||
[assembly: AssemblyTrademark("")] | |||
[assembly: AssemblyCulture("")] | |||
[assembly: AssemblyVersion("0.3.0.0")] | |||
[assembly: AssemblyFileVersion("0.3.0.0")] | |||
[assembly: AssemblyVersion("0.3.1.0")] | |||
[assembly: AssemblyFileVersion("0.3.1.0")] |
@@ -18,6 +18,7 @@ namespace Discord | |||
internal Role(string id, string serverId, DiscordClient client) | |||
{ | |||
Id = id; | |||
ServerId = serverId; | |||
_client = client; | |||
} | |||
@@ -24,8 +24,8 @@ namespace Discord | |||
public string DefaultChannelId { get { return Id; } } | |||
public Channel DefaultChannel { get { return _client.GetChannel(DefaultChannelId); } } | |||
internal ConcurrentDictionary<string, bool> _members; | |||
public IEnumerable<User> Members { get { return _members.Keys.Select(x => _client.GetUser(x)); } } | |||
internal ConcurrentDictionary<string, Membership> _members; | |||
public IEnumerable<Membership> Members { get { return _members.Values; } } | |||
internal ConcurrentDictionary<string, bool> _bans; | |||
public IEnumerable<User> Bans { get { return _bans.Keys.Select(x => _client.GetUser(x)); } } | |||
@@ -41,7 +41,7 @@ namespace Discord | |||
{ | |||
Id = id; | |||
_client = client; | |||
_members = new ConcurrentDictionary<string, bool>(); | |||
_members = new ConcurrentDictionary<string, Membership>(); | |||
_bans = new ConcurrentDictionary<string, bool>(); | |||
} | |||
@@ -50,24 +50,33 @@ namespace Discord | |||
return Name; | |||
} | |||
internal void AddMember(string id) | |||
internal void AddMember(Membership membership) | |||
{ | |||
_members.TryAdd(id, true); | |||
_members[membership.UserId] = membership; | |||
} | |||
internal bool RemoveMember(string id) | |||
internal Membership RemoveMember(string userId) | |||
{ | |||
bool ignored; | |||
return _members.TryRemove(id, out ignored); | |||
Membership result = null; | |||
_members.TryRemove(userId, out result); | |||
return result; | |||
} | |||
public Membership GetMembership(User user) | |||
=> GetMembership(user.Id); | |||
public Membership GetMembership(string userId) | |||
{ | |||
Membership result = null; | |||
_members.TryGetValue(userId, out result); | |||
return result; | |||
} | |||
internal void AddBan(string id) | |||
internal void AddBan(string banId) | |||
{ | |||
_bans.TryAdd(id, true); | |||
_bans.TryAdd(banId, true); | |||
} | |||
internal bool RemoveBan(string id) | |||
internal bool RemoveBan(string banId) | |||
{ | |||
bool ignored; | |||
return _bans.TryRemove(id, out ignored); | |||
return _bans.TryRemove(banId, out ignored); | |||
} | |||
} | |||
} |